2013-08-16 114 views
1

鑑於類:後期綁定異常調用泛型類型的泛型方法在C#

public class A<T> 
{ 
    public void Handle(object payload) 
    { 
     if(IsEnumerable(payload)) //assume this works 
     { 
      var closedMethod = GetType() 
       .GetMethod(
        "HandleIEnumerable", 
        BindingFlags.NonPublic | BindingFlags.Instance) 
       .MakeGenericMethod(
        GetFirstGenericArgument(typeof(T))); 
      closedMethod 
       .Invoke(
        this, 
        null); //Exception thrown by the Invoke operation 
          //Debugging shows type as HandleIEnumerable[T] 
      return; 
     } 
     //handle other things 
    } 

    //This was added because in the above, I can't interact with "T" 
    // as IEnumerable<U> without using reflection 
    // to jump through the hoops 
    private void HandleIEnumerable<U>(object payload) 
    { 
     foreach (var element in payload as IEnumerable<U>) 
     { 
      // do something to element 
     } 
    } 

    private bool IsEnumerable(object payload) 
    { 
     var theType = typeof(T); 
     return 
      theType.IsGenericType 
      && (theType.GetGenericTypeDefinition() == typeof(IEnumerable<>)); 
    } 

    private Type GetFirstGenericArgument(Type t) 
    { 
     return t.GetGenericTypeDefinition().GetGenericArguments()[0]; 
    } 
} 

一個例外是由測試用例暴露:

[TestMethod] 
    public void A_Handle_IEnumerable() 
    { 
     new ClassLibrary1.A<IEnumerable<int>>() 
      .Handle(new List<int> { 1, 2, 3, 4 } as IEnumerable<int>); 
    } 

異常詳細信息:

System.InvalidOperationException:對ContainsGenericParam類型或方法執行的後期操作不能爲 eters是 是真的。

我使用的Windows 7

1的Visual Studio 2013預覽快遞桌面:如何使這種方法的工作?

2:泛型是否真的是在這裏做的正確的事情,如果沒有,建議?

*** 查看回答詳情 ****

正確實施是隻使用了IEnumerable [非通用]這樣做:

public class A<T> 
{ 
    public void Handle(object payload) 
    { 
     var enumerable = payload as IEnumerable; 
     if(enumerable != null) 
     { 
      //do work on enumerable 
     } 
    } 
} 

啊,C#的缺點是在職培訓。所有的痛點都是因爲需要IEnumerable的通用版本,而這並不是必需的 - 只是認爲這是因爲我不知道非通用形式。

+3

你想用這段代碼做什麼? – alex

+0

接收未知類型的對象,如果它是IEnumerable迭代它並執行某些操作,並且如果它不是IEnumerable,則執行其他操作。我嘗試了一些更簡單的方法,但似乎一切都需要輸入IEnumerable ,而「某些東西」似乎只能通過反射來獲得。 – PatrickV

回答

0
  1. 您的GetFirstGenericArgument()是錯誤的。
    調用GetGenericTypeDefinition()返回底層的開放泛型類型。
    它的類型參數是T

    相反,您應該編寫t.GetGenericArguments()[0],它將獲得關閉類型的泛型類型參數的值。

  2. 否;你的代碼沒有任何意義。
    你想要做什麼?

    我懷疑你真正想要寫

    public class CollectionHandler<T> { 
        public void Handle(IEnumerable<T> collection) { 
         // Look ma, no reflection! 
        } 
    } 
    
+0

哪裏和如何將我的代碼掛鉤?我給了它一個鏡頭,但無法推斷出類型。 – PatrickV

+0

@PatrickV:哪個? – SLaks

+1

@PatrickV:看到你的問題的評論後,你實際上想要使用非泛型的'System.Collections.IEnumerable',並完全擺脫泛型。 – SLaks

0

看起來像你想,當你收到的IEnumerable<T>實例調用方法HandleIEnumerable<U>和U繼承T.

你可以這樣做通過指定U應該從T繼承:

private void HandleIEnumerable<U>(IEnumerable<U> payload) where U :T 
    { 
    ... 
    } 

並且在你的Handle方法中:

public void Handle(object payload) 
{ 
    if(IsEnumerable(payload)) 
    { 
     HandleIEnumerable((IEnumerable<U>)payload); 
    } 
} 
+0

對T沒有限制。當且僅當T是一個IEnumerable 時,我想遍歷該枚舉並做一些事情。但T也可能是一個字符串,在這種情況下,我不想這樣做。 – PatrickV