注意:此问题涉及技术方面,不关于设计决策。回答或评论不同的设计不回答这个问题,因为我只对这个特定问题的技术方面的性质感兴趣。
在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();
...
}
哪个也有效,但后来我意识到:&#39; 嘿!为什么不 return typeof(T).Name
?&#39;
结果发现它返回字符串"Object"
,而我期望与之前的实现相同的结果(例如"MyClass"
)。
甚至可以获得预期的类型?在处理开放泛型类型T
时,似乎所有信息都丢失了。
为什么我没有达到预期的类型? C#
的这种特殊行为的技术细节是什么?
答案 0 :(得分: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