2011-04-20 84 views
0

有一個很有趣的情況,似乎無法找到任何對周圍的反射,繼承和泛型腹板混凝土。使用實體框架抽象類

要開始使用:

我有一個抽象基類化,可稱爲:

public abstract class ItemBase 
{ 
    // default properties 
} 

ItemBase就變成了我的超類的抽象實體,稱爲項目:

public abstract class Item 
{ 
    // some extra properties 
} 

這背後的想法是構造將繼承Item的附加屬性集的實體:

public partial class City : Item {} 

現在,在測試方法我想使用反射來調用通過實體的方法,並返回任何數據,在什麼都形成,從方法回來。

假設,出於測試目的,我們在狀態的方法,返回所有主要城市的集合:

public List<City> GetAllMajorCities() {} 

在我的存根我可能有一個測試,以獲得所有城市:

List<Item> cities = this.InvokeGenericMethod<Item>("State", "GetAllMajorCities", args); 

然後InvokeGenericMethod(字符串,字符串,對象[]參數)看起來像:

public IEnumerable<T> InvokeGenericMethod<Item>(string className, string methodName, object[] args) 
{ 
    Type classType = className.GetType(); // to get the class to create an instance of 
    object classObj = Activator.CreateInstance(classType); 
    object ret = classType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, classObj, args); 
} 

從理論上講,從給出的實例中,「RET」的值應該是一個IEnumerable類型,然而,返回類型,如果加入到手錶investivage,返回列表,如果我檢查RET值:

if (ret is IEnumerable<T>) 

它忽略了檢查。

如果我改變

public List<City> GetAllMajorCities() {} 

public List<ItemBase> GetAllMajorCities() {} 

似乎要堅持繼承和允許我丟給IEnumberable。

我在這裏完全難住了。

任何意見,建議,將不勝感激。

感謝,

埃裏克

+0

你能重新檢查你的代碼嗎?我覺得有一些東西混在一起。我猜你的InvokeGenericMethod不起作用。例如,className.GetType()將全部返回類型字符串。 – Achim 2011-04-20 07:23:01

+0

嗨Achim,上面的代碼是一個真正的道歉,如果它有點混亂的例子。在綁定一個下拉列表時,我使用反射到類的全名,類的字符串格式的命名空間,然後將其作爲一個字符串傳遞給我的InvokeGenericMethod。 – JadedEric 2011-04-20 10:09:10

回答

3

您是否可能使用Framework 3.5? .net 4.0中引入了泛型協變和逆變。因此,下面是不可能在Framework 3.5:

class ItemBase { } 
class Item : ItemBase { } 
class City : Item { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IEnumerable<City> cities = new List<City>(); 
     IEnumerable<Item> items = cities; // Compile error here. IEnumerable<Item> is not a supertype of IEnumerable<City>. 
    } 
} 

注意以下(這是你要實現的目標)將不會在.NET 4.0中,即使工作:

List<Item> cities = new List<City>(); 

爲什麼這不正常嗎?因爲必須可以向List<Item>添加任意的Item。但是,顯然,cities.Add(new Person());不能工作(因爲cities的「真實」(=靜態)類型是List<City>)。因此,List<Item>永遠不可能是List<City>的超類型。

無法項目添加到一個IEnumerable,這就是爲什麼有IEnumerable<City>IEnumerable<Item>之間的關係亞型(但只能在.NET 4.0中,如上面提到的)。

+0

嗨Heinzi。謝謝你的解釋,這是有道理的。理解,我錯誤地認爲是因爲我們有一個超類的ItemBase,子類將在被反射時自動定義。對我來說有點疏忽。 – JadedEric 2011-04-20 10:05:00

1

你可以嘗試這樣的事:

 Type type = ret.GetType(); 
     Type listType = typeof(IEnumerable<T>); 
     if (type == listType || type.IsSubclassOf(listType)) 
     { 
      // 
     } 
1

首先,這是錯誤的:

Type classType = className.GetType(); 

此結構將產生類型className這是String但不是名稱爲stor的類型編輯於className

一個更好,更類型安全的方法是:

public IEnumerable<TItem> InvokeGenericMethod<TItem, TContainer>(...) 
    where TItem : ItemBase 
    where TContainer : class, new() 
{ 
    TContainer container = new TContainer(); 
    ... 
} 

更新:萬一TContainer類型在哪裏InvokeGenericMethod被稱爲地方靜態已知,對一臉的中靜態Type.GetType方法來解析其字符串名稱的實際名稱。在最簡單的情況下,Type.GetType(String)方法訪問您的類型的組件限定名稱,例如, "MyNamespace.City, MyAssembly"

+0

您好Ondrej,您的提案將在實際類已知它是「純粹」形式的情況下工作,但是,我有一個在我的控制下的下拉框,它將實體(類)的名稱列爲字符串值。我需要從程序集中獲取關聯字符串的基礎類型。我會進一步調查,因爲如果我改變自己的邏輯,我覺得你提出的解決方案可能有價值。 – JadedEric 2011-04-20 10:07:06

+0

@JadedEric Undestood並相應地更新了我的答案。但是,如果您可以將自己的邏輯轉變爲更安全的解決方案,可能會避免反思,您將來通常會從中受益。 – 2011-04-20 10:53:35