1

给定班级:

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 为 true 的类型或方法执行后期绑定操作。

我在 Windows 7 上使用 Visual Studio 2013 preview express 桌面。

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,这不是必需的 - 只是认为这是因为我不知道非通用形式。

4

2 回答 2

0
  1. GetFirstGenericArgument()错了。
    调用GetGenericTypeDefinition()返回底层的开放泛型类型。
    它的类型参数是T.

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

  2. 不; 你的代码没有任何意义。
    你到底想做什么?

    我怀疑你真的想写

    public class CollectionHandler<T> {
        public void Handle(IEnumerable<T> collection) { 
            // Look ma, no reflection!
        }
    }
    
于 2013-08-16T15:47:16.960 回答
0

HandleIEnumerable<U>当您收到实例IEnumerable<T>并且 U 继承自 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);
    }
}
于 2013-08-16T15:51:01.813 回答