GenericTypeDefinitionName from IEnumerable<object>
本文关键字:object gt from lt GenericTypeDefinitionName IEnumerable | 更新日期: 2023-09-27 17:54:24
注意: 这个问题是关于技术方面的,不是关于设计决策。回答或评论一个不同的设计并不能回答这个问题,因为我只对这个特定问题的技术方面的本质感兴趣。
在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();
}
然后从MyMethod()
中调用GetGenericTypeDefinitionName()
,如下所示:
public void MyMethod(IEnumerable<object> list)
{
...
var name = list.GetGenericTypeDefinitionName();
...
}
也可以,但后来我意识到:'嘿!为什么不直接 return typeof(T).Name
呢?的
结果是它返回字符串"Object"
,而我期望与以前的实现相同的结果(例如"MyClass"
)。
有可能得到预期的类型吗?在处理开放泛型T
时,似乎所有信息都丢失了。为什么我没有得到预期的类型?C#
的这种特殊行为的技术细节是什么?
如果您使用通用方差将某种参考类型T
的IEnumerable<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