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

C# 在C中调用泛型类型的泛型方法的后期绑定异常#,c#,generics,reflection,C#,Generics,Reflection,鉴于班级: public class A<T> { public void Handle(object payload) { if(IsEnumerable(payload)) //assume this works { var closedMethod = GetType() .GetMethod( "HandleIEnumerable",

鉴于班级:

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];
    }
}
公共A类
{
公共无效句柄(对象有效负载)
{
if(IsEnumerable(payload))//假设这是可行的
{
var closedMethod=GetType()
.GetMethod(
“可枚举的”,
BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(
GetFirstGenericArgument(typeof(T));
封闭法
.调用(
这
null);//调用操作引发的异常
//调试将类型显示为HandleEnumerable[T]
返回;
}
//处理其他事情
}
//这是因为在上面,我无法与“t”交互
//在不使用反射的情况下是不可数的
//跳环
私有void HandleIEnumerable(对象负载)
{
foreach(有效负载中的var元素为IEnumerable)
{
//对元素做些什么
}
}
私有布尔值可计算(对象有效负载)
{
变量类型=类型(T);
返回
type.IsGenericType
&&(type.GetGenericTypeDefinition()==typeof(IEnumerable));
}
私有类型GetFirstGenericArgument(类型t)
{
返回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>);
    }
[TestMethod]
public void A_Handle_IEnumerable()
{
新类库1.A()
.Handle(新列表{1,2,3,4}为IEnumerable);
}
例外情况详情:

System.InvalidOperationException:不能执行后期绑定操作 对包含GenericParameters的类型或方法执行 对

我正在Windows 7上使用Visual Studio 2013预览express桌面

1:我如何使这种方法起作用

2:在这里泛型真的是正确的吗?如果不是,建议

***答案详细信息***

正确的实现方法是只使用IEnumerable[非泛型]来实现:

public class A<T>
{
    public void Handle(object payload)
    {
        var enumerable = payload as IEnumerable;
        if(enumerable != null)
        {
            //do work on enumerable
        }
    }
}
公共A类
{
公共无效句柄(对象有效负载)
{
var enumerable=作为IEnumerable的有效负载;
if(可枚举!=null)
{
//做可枚举的工作
}
}
}
啊,C#as在职培训的缺点。所有的痛点都是因为需要IEnumerable的泛型版本,这是不需要的——只是我认为这是因为我不知道非泛型形式

  • 您的
    GetFirstGenericArgument()
    错误。
    调用
    GetGenericTypeDefinition()
    返回基础的开放泛型类型。
    它的类型参数是
    T


    相反,您应该编写
    t.GetGenericArguments()[0]
    ,它将获取关闭类型的泛型类型参数的值

  • 没有;您的代码没有任何意义。
    你到底想干什么?

    我怀疑你真的想写作

    public class CollectionHandler<T> {
        public void Handle(IEnumerable<T> collection) { 
            // Look ma, no reflection!
        }
    }
    
    公共类CollectionHandler{
    公共无效句柄(IEnumerable集合){
    //看,妈妈,没有反应!
    }
    }
    

  • 当您接收到
    IEnumerable
    的实例且U从T继承时,似乎要调用方法
    HandleEnumerable

    通过指定U应该从T继承,您可以在不进行反射的情况下执行此操作:

      private void HandleIEnumerable<U>(IEnumerable<U> payload) where U :T
      {
        ...
      }
    
    private void handlei可枚举(IEnumerable payload),其中U:T
    {
    ...
    }
    
    在你的处理方法中:

    public void Handle(object payload)
    {
        if(IsEnumerable(payload)) 
        {
           HandleIEnumerable((IEnumerable<U>)payload);
        }
    }
    
    公共无效句柄(对象负载)
    {
    if(可计算(有效载荷))
    {
    HandleEnumerable((IEnumerable)有效载荷);
    }
    }
    
    你想用这段代码做什么?接收一个未知类型的对象,如果它是IEnumerable,则对它进行迭代并执行某些操作,如果它不是IEnumerable,则执行其他操作。我尝试了一些简单得多的方法,但似乎每件事都需要输入IEnumerable,而“something”似乎只能通过反射来获取。这将在哪里以及如何与我的代码挂钩?我试了一下,但无法推断类型。@PatrickV:在看到对您的问题的评论后,您实际上想使用非泛型的
    System.Collections.IEnumerable
    ,并完全摆脱泛型。谢谢SLaks,这就成功了。主帖子更新了详细信息。对T没有约束。当且仅当T是IEnumerable时,我想迭代该枚举并做一些事情。但是T也可能是一个字符串,在这种情况下,我不想这样做。