在C#中调用Generic类型的通用方法的后绑定异常

时间:2013-08-16 15:44:24

标签: c# generics reflection

鉴于课程:

public class A<T>
{
    public void Handle(object payload)
    {
        if(IsEnumerable(payload)) //assume this works
        {
            var closedMethod = GetType()
                .GetMethod(
                    "HandleIEnumerable",
                    BindingFlags.NonPublic | BindingFlags.Instance)
                .MakeGenericMethod(
                    GetFirstGenericArgument(typeof(T)));
            closedMethod
                .Invoke(
                    this,
                    null); //Exception thrown by the Invoke operation
                           //Debugging shows type as HandleIEnumerable[T]
            return;
        }
        //handle other things
    }

    //This was added because in the above, I can't interact with "T" 
    //  as IEnumerable<U> without using reflection
    //  to jump through the hoops
    private void HandleIEnumerable<U>(object payload)
    {
        foreach (var element in payload as IEnumerable<U>) 
        {
            // do something to element
        }
    }

    private bool IsEnumerable(object payload) 
    {
        var theType = typeof(T);
        return 
            theType.IsGenericType 
            && (theType.GetGenericTypeDefinition() == typeof(IEnumerable<>));
    }

    private Type GetFirstGenericArgument(Type t)
    {
        return t.GetGenericTypeDefinition().GetGenericArguments()[0];
    }
}

测试用例暴露了异常:

    [TestMethod]
    public void A_Handle_IEnumerable()
    {
        new ClassLibrary1.A<IEnumerable<int>>()
            .Handle(new List<int> { 1, 2, 3, 4 } as IEnumerable<int>);
    }

异常详情:

  

System.InvalidOperationException:不能进行后期绑定操作   对ContainsGenericParameters所属的类型或方法执行   真。

我在Windows 7上使用Visual Studio 2013预览快速桌面。

1:我如何使这种方法有效?

2:仿制药在这里是否真的是正确的,如果没有,建议?

*** 回答详情 ****

正确的实现是使用IEnumerable [non-generic]来执行此操作:

public class A<T>
{
    public void Handle(object payload)
    {
        var enumerable = payload as IEnumerable;
        if(enumerable != null)
        {
            //do work on enumerable
        }
    }
}

啊,C#作为在职培训的缺点。所有的痛点都是由于需要IEnumerable的通用版本,这是不需要的 - 只是因为我不知道非泛型形式。

2 个答案:

答案 0 :(得分:0)

  1. 您的GetFirstGenericArgument()错了 调用GetGenericTypeDefinition()将返回基础开放泛型类型 它的类型参数是T
    相反,您应该编写t.GetGenericArguments()[0],它将获得封闭类型的泛型类型参数的值。

  2. 没有;你的代码没有任何意义。
    你究竟想做什么?
    我怀疑你真的想写

    public class CollectionHandler<T> {
        public void Handle(IEnumerable<T> collection) { 
            // Look ma, no reflection!
        }
    }
    

答案 1 :(得分:0)

当您收到HandleIEnumerable<U>的实例且U从T继承时,您似乎想要调用方法IEnumerable<T>

通过指定U应该从T:

继承,你可以在没有反射的情况下完成
  private void HandleIEnumerable<U>(IEnumerable<U> payload) where U :T
  {
    ...
  }

在你的Handle方法中:

public void Handle(object payload)
{
    if(IsEnumerable(payload)) 
    {
       HandleIEnumerable((IEnumerable<U>)payload);
    }
}