2010-01-14 378 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