2016-07-04 27 views
4

注意這個問題是關於技術方面,而不是設計決策。回答或評論不同的設計不是回答這個問題,因爲我只對這個特定問題的技術方面的性質感興趣。GenericTypeDefinitionName自IEnumerable <object>

C# 6.0我有這樣的方法,在那裏我傳遞一個IEnumerable<T>

public void MyMethod(IEnumerable<object> list) { ... } 

假設主叫用戶呼叫它的一個MyClass[]陣列上。
我要的是泛型類型定義的類名,我有這樣的方法實現:

public void MyMethod(IEnumerable<object> list) 
{ 
    ... 
    var name = 
     from abstraction in list.GetType().GetInterfaces() 
     where abstraction.IsGenericType 
     && abstraction.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
     from genericArgumentType in abstraction.GetGenericArguments() 
     select genericArgumentType.Name; 
    ... 
} 

現在,在這種情況下,(該方法的主體內),這正確返回的名稱類(例如字符串"MyClass")。所以我試圖重構到這個開放的通用擴展方法,像這樣:

public static string GetGenericTypeDefinitionName<T>(this IEnumerable<T> list) 
{ 
    var name = 
     from abstraction in list.GetType().GetInterfaces() 
     where abstraction.IsGenericType 
     && abstraction.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
     from genericArgumentType in abstraction.GetGenericArguments() 
     select genericArgumentType.Name; 

    return name.Single(); 
} 

然後調用GetGenericTypeDefinitionName()MyMethod()內,像這樣:

public void MyMethod(IEnumerable<object> list) 
{ 
    ... 
    var name = list.GetGenericTypeDefinitionName(); 
    ... 
} 

也可以工作,但後來我意識到:「嘿!爲什麼不只是return typeof(T).Name'

事實證明,它返回字符串"Object",而我期望與以前的實施相同的結果(例如"MyClass")。

它甚至有可能得到預期的類型?似乎在處理開放式泛型T時,所有信息都會丟失。 此外,爲什麼我沒有得到預期的類型? C#的這種特殊行爲的技術細節是什麼?

+0

你能告訴你究竟是如何把它稱爲使'的typeof(T).Name'返回' 「對象」'? –

+0

你是否在使用通用方差? 'IEnumerable '可以被分配給'IEnumerable '。 –

+0

@RenéVogt我編輯了這個問題來展示如何和在哪裏調用擴展方法。 – QuantumHive

回答

5

如果您使用通用差異將IEnumerable<T>的某些參考類型T指定爲IEnumerable<object>,則會出現您所描述的情況。

編譯器打算使用它知道在編譯時選擇<T>,在這種情況下爲object。但是,如果您使用反射,您將獲得原始名稱 - 因爲實際對象不受變化技巧的影響。

static void Main() 
{ 
    IEnumerable<Foo> typed = new Foo[0]; 
    IEnumerable<object> untyped = typed; 

    Console.WriteLine(typed.GetByGenerics());  // Foo 
    Console.WriteLine(untyped.GetByGenerics()); // Object 

    Console.WriteLine(typed.GetByReflection()); // Foo 
    Console.WriteLine(untyped.GetByReflection()); // Foo 
} 
public static string GetByGenerics<T>(this IEnumerable<T> list) 
{ 
    return typeof(T).Name; 
} 
public static string GetByReflection<T>(this IEnumerable<T> list) 
{ 
    var name = 
     from abstraction in list.GetType().GetInterfaces() 
     where abstraction.IsGenericType 
     && abstraction.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
     from genericArgumentType in abstraction.GetGenericArguments() 
     select genericArgumentType.Name; 

    return name.Single(); 
} 

這是因爲你實際上調用

Console.WriteLine(GetByGenerics<Foo>(typed));  // Foo 
Console.WriteLine(GetByGenerics<Object>(untyped)); // Object 
+0

都會寫在控制檯的實際類型? –

+0

@Ehsan我已經在編輯 –

+0

的示例中添加了控制檯輸出,我想我明白了。因此,在我的問題中,'MyMethod'在其參數中定義了一個編譯時類型('IEnumerable '),'GetByGenerics'例子永遠不會知道基於開放泛型類型'T'的原始類型('IEnumerable '') ,對嗎?因爲這是在編譯時定義的,並且不能由編譯器推斷出來? – QuantumHive

相關問題