【发布时间】:2010-01-14 04:02:29
【问题描述】:
感谢 Jon Skeet 在this 问题中的回答,我有以下工作:
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();
}
}
如上所述,我能看到的唯一区别是:
- 不同的返回类型(
T有效,IEnumerable<T>无效)[编辑:这是不对的,第一个版本使用BaseItem,而不是T;哎呀] - 重载(
GetItem没有重载,GetList有几个;我只需要GetList()的委托,没有参数
更新 1:Sam 帮我查明了一些问题。如果委托的返回类型是通用的(例如IEnumerable<BaseItem>),那么当我尝试交换基类/派生类型时,它会令人窒息。有什么方法可以声明我的GetList 方法,如下所示?我需要能够表明T 继承自BaseItem,但如果可以的话,它对我来说就可以了。
public static IEnumerable<BaseItem> GetList<T>() where T : class
另一种选择是“泛化”我的委托声明。我能找到的所有示例都使用泛型作为参数,而不是返回类型。我该怎么做(它会引发编译器错误,因为 T 未定义,它不会让我使用 where 约束):
public delegate IEnumerable<T> GetListDelegate();
【问题讨论】:
-
在我发布此之前所做的所有阅读中,我知道类型不匹配是导致此异常的一个常见原因。在上面的每个示例中,我在返回调用上都设置了一个断点,并且每种情况下变量方法的类型似乎几乎相同。我看不出有什么不妥。只是想我会添加那个花絮。
-
为什么这变成了社区维基?
-
哇,你自己的帖子编辑得够多了,它就自动变成了维基?这真是太愚蠢了。
标签: c# generics delegates methodinfo