この質問での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
戻り値の型とオーバーロードが異なるメソッドに同じことを適用しようとすると (これらは私が思いつく唯一の違いです)、迷惑な "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()パラメーターのないデリゲートのみが必要です
Update1: Sam は、いくつかの問題を特定するのを手伝ってくれました。デリゲートの戻り値の型がジェネリック (例: IEnumerable<BaseItem>) の場合、基本型と派生型を交換しようとすると窒息します。以下のようにメソッドを宣言するGetList方法はありますか? Tがから継承されていることを示すことができる必要がありますがBaseItem、それができれば問題なく動作します。
public static IEnumerable<BaseItem> GetList<T>() where T : class
もう 1 つのオプションは、デリゲート宣言を「ジェネリック化」することです。私が見つけることができるすべての例は、戻り値の型ではなく、params のジェネリックを使用しています。これを行うにはどうすればよいですか (原因が定義されていないコンパイラ エラーがスローされ、制約Tを使用できません):where
public delegate IEnumerable<T> GetListDelegate();