来自IEnumerable <object>的GenericTypeDefinitionName

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#什么?

Mar*_*ell 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();
}
Run Code Online (Sandbox Code Playgroud)

这是因为你实际上正在打电话

Console.WriteLine(GetByGenerics<Foo>(typed));      // Foo
Console.WriteLine(GetByGenerics<Object>(untyped)); // Object
Run Code Online (Sandbox Code Playgroud)