Qua*_*ive 4 .net c# generics reflection
注意:这个问题涉及技术方面,而不是设计决策.回答或评论不同的设计并不能回答这个问题,因为我只对这个特定问题的技术方面的性质感兴趣.
在C# 6.0
我这个方法在那里我传递一个IEnumerable<T>
:
public void MyMethod(IEnumerable<object> list) { ... }
Run Code Online (Sandbox Code Playgroud)
假设调用者在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;
...
}
Run Code Online (Sandbox Code Playgroud)
现在在这种情况下(在方法体内),这正确地返回类的名称(例如字符串"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();
}
Run Code Online (Sandbox Code Playgroud)
然后GetGenericTypeDefinitionName()
从内部打电话MyMethod()
:
public void MyMethod(IEnumerable<object> list)
{
...
var name = list.GetGenericTypeDefinitionName();
...
}
Run Code Online (Sandbox Code Playgroud)
这也有效,但后来我意识到:' 嘿!为什么不 return typeof(T).Name
呢?"
结果发现它返回字符串"Object"
,而我期望与"MyClass"
之前的实现相同的结果(例如).
是否有可能获得预期的类型?在处理开放泛型类型时,似乎所有信息都丢失了T
.为什么我没有得到预期的类型?这种特殊行为的技术细节是C#
什么?
如果您使用泛型方差为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();
}
Run Code Online (Sandbox Code Playgroud)
这是因为你实际上正在打电话
Console.WriteLine(GetByGenerics<Foo>(typed)); // Foo
Console.WriteLine(GetByGenerics<Object>(untyped)); // Object
Run Code Online (Sandbox Code Playgroud)