感谢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
另一种选择是将我的委托声明“泛化”。我可以找到的所有示例都使用params的泛型,而不是返回类型。我该怎么做(它抛出编译器错误导致T
未定义,并且它不允许我使用where
约束):
public delegate IEnumerable<T> GetListDelegate();
答案 0 :(得分: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 :(得分: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以声明协方差(或逆变,我不确定哪个)。