感谢Jon Skeet在这个问题中的回答,我现在已经有了以下的工作方案:
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
当我试图把同样的东西应用到一个有不同返回类型和重载方法的函数时(这是我能想到的唯一区别),我在调用CreateDelegate
时会得到一个让人恼火的“ArgumentException:Error binding to target method。”下面是一个可工作但会出错的示例代码,只需将其复制/粘贴到控制台应用程序中即可。
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()
委托
IEnumerable<BaseItem>
),当我尝试交换基类/派生类时会出现问题。有没有办法像下面这样声明我的 GetList
方法?我需要能够表示 T
继承自 BaseItem
,但如果我能够这样做,那对我来说就可以正常工作了。public static IEnumerable<BaseItem> GetList<T>() where T : class
另一种选择是将我的委托声明“泛型化”。我能找到的所有示例都使用参数的泛型,而不是返回类型的泛型。我该怎么做?(它会抛出编译器错误,因为未定义 T,并且它不允许我使用 where 约束)
public delegate IEnumerable<T> GetListDelegate();