2010-01-14 376 views
3

由于乔恩斯基特在this问题的答案,我有以下工作:的MethodInfo,createDelegate方法和泛型方法

public delegate BaseItem GetItemDelegate(Guid itemID); 

public static class Lists 
{ 
    public static GetItemDelegate GetItemDelegateForType(Type derivedType) 
    { 
    MethodInfo method = typeof(Lists).GetMethod("GetItem"); 
    method = method.MakeGenericMethod(new Type[] { derivedType }); 
    return (GetItemDelegate)Delegate.CreateDelegate(typeof(GetItemDelegate), method); 
    } 

    public static T GetItem<T>(Guid itemID) where T : class { // returns an item of type T ... } 
} 

public class DerivedItem : BaseItem { } 

// I can call it like so: 
GetItemDelegate getItem = Lists.GetItemDelegateForType(typeof(DerivedItem)); 
DerivedItem myItem = getItem(someID); // this works great 

当我尝试运用同样的事情的方法具有不同的返回类型和过载(那些是我能想出的唯一区别),我得到一个恼人的“ArgumentException:错误绑定到目标方法。”致电CreateDelegate。以下是一个可以获取错误的实例,只需复制/粘贴到控制台应用程序中。

public delegate IEnumerable<BaseItem> GetListDelegate(); 

public class BaseItem { } 
public class DerivedItem : BaseItem { } 

public static class Lists 
{ 
    public static GetListDelegate GetListDelegateForType(Type itemType) 
    { 
    MethodInfo method = typeof(Lists).GetMethod("GetList", Type.EmptyTypes); // get the overload with no parameters 
    method = method.MakeGenericMethod(new Type[] { itemType }); 
    return (GetListDelegate)Delegate.CreateDelegate(typeof(GetListDelegate), method); 
    } 

    // this is the one I want a delegate to, hence the Type.EmptyTypes above 
    public static IEnumerable<T> GetList<T>() where T : class { return new List<T>(0); } 
    // not the one I want a delegate to; included for illustration 
    public static IEnumerable<T> GetList<T>(int param) where T : class { return new List<T>(0); } 

    public static Type GetItemType() 
    { // this could return any type derived from BaseItem 
    return typeof(DerivedItem); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
    Type itemType = Lists.GetItemType(); 
    GetListDelegate getList = Lists.GetListDelegateForType(itemType); 
    IEnumerable<BaseItem> myList = (IEnumerable<BaseItem>)getList(); 
    } 
} 

正如上面提到的,我能看到的唯一区别是:

  1. 不同的返回类型(T作品,IEnumerable<T>不)[编辑:这是不对的,第一个版本的用途BaseItem,而不是T;哎呀]
  2. 重载(GetItem没有超载,GetList有几个,我只需要在委托GetList()没有PARAMS

UPDATE1:萨姆帮我找出一些问题,如果的返回类型委托是通用的(例如IEnumerable<BaseItem>),当我尝试交换基类/派生类型时,它会窒息。有没有什么办法可以声明我的GetList方法如下?我需要能够指示继承自BaseItem,但是如果我那么它可以为我工作。

public static IEnumerable<BaseItem> GetList<T>() where T : class 

另一种选择是“通用化”我的委托声明。我可以找到的所有示例都使用通用参数,而不是返回类型。我如何做到这一点(它抛出一个编译器错误原因T是不确定的,它不会让我用where约束):

public delegate IEnumerable<T> GetListDelegate(); 
+0

在发布之前的所有阅读中,我知道类型不匹配是此异常的一个常见原因。我在上面每个例子中的返回调用中设置了一个断点,并且在每种情况下变量方法的类型看起来几乎相同。我什么都看不到。只是想我会添加那个珍闻。 – sliderhouserules 2010-01-14 04:20:53

+0

为什么这会变成社区维基? – sliderhouserules 2010-01-14 08:03:13

+1

哇,你编辑自己的帖子够了,它会自动变成一个维基?这是该死的愚蠢。 – sliderhouserules 2010-01-14 08:18:12

回答

2

我已经得到了这个工作,宣布代表只是IEnumerable。这允许它创建委托。那时剩下的只是基本的铸造。以下更改修复了上面的第二个代码块。

// declare this as non-generic 
public delegate IEnumerable GetListDelegate(); 

// do some cast-fu to get the list into a workable form 
List<BaseItem> myList = getList().Cast<BaseItem>().ToList(); 

然后我可以做myList.Sort()和所有其他的东西,我想在工作中我制做。

1

进行一些小的修改后得到第二个例子中编译,我能够运行它并获取并调用委托。

using System; 
using System.Collections.Generic; 
using System.Reflection; 

namespace ConsoleApplication1 
{ 
    public delegate IEnumerable<BaseItem> GetListDelegate(); 

    public class BaseItem { } 
    public class DerivedItem : BaseItem { } 

    public static class Lists 
    { 
     public static GetListDelegate GetListDelegateForType(Type derivedType) 
     { 
      MethodInfo method = typeof(Lists).GetMethod("GetList", Type.EmptyTypes); // get the overload with no parameters 
      method = method.MakeGenericMethod(new[] { derivedType }); 
      return (GetListDelegate)Delegate.CreateDelegate(typeof(GetListDelegate), method); // *** this throws an exception *** 
     } 

     // this is the one I want a delegate to, hence the Type.EmptyTypes above 
     public static IEnumerable<T> GetList<T>() where T : class 
     {// returns a collection of T items ... 
      return new T[0]; 
     } 

     // not the one I want a delegate to; included for illustration, maybe my different GetMethod() is my problem? 
     public static IEnumerable<T> GetList<T>(int param) where T : class 
     { // returns a collection of T items ... 
      return new T[0]; 
     } 
    } 

    public class GenericDelegate 
    { 
     public static void Test() 
     { 

      // I would call it like so, but first line gets exception, where indicated above 
      GetListDelegate getList = Lists.GetListDelegateForType(typeof(BaseItem)); 
      IEnumerable<BaseItem> myList = getList(); 
     } 
    } 
} 

我不知道你是如何得到你的第二个例子编译。这里似乎有问题。

public delegate IEnumerable<BaseItem> GetListDelegate(); 

GetListDelegate getList = Lists.GetListDelegateForType(typeof(DerivedList)); 
IEnumerable<DerivedList> myList = getList(); 

该委托被声明为返回IEnumerable,但随后调用它并将结果赋给IEnumerable。这在C#3.5中不受支持。它在C#4中,但它需要以不同的方式声明BaseItem/DerivedList来声明协方差(或反例,我不确定哪一个)。

+0

我在工作时从大型系统中提取了所有这些代码,并更改了类型名称和内容,以便制作可展示样本。我应该制作了一个示例应用程序,并首先与它一起玩。将DerivedList类型更改为DerivedItem。这是一个复制/粘贴/替换错误。我已经编辑我的问题来解决这个问题。考虑到这一点,你能否重申你的最后一段,因为我没有在那里跟踪你。 – sliderhouserules 2010-01-14 04:47:33