2013-07-30 130 views
3

假設我有一個這樣的類,包含一個通用的方法,用out參數:如何通過反射調用帶參數的泛型方法?

public class C 
{ 
    public static void M<T>(IEnumerable<T> sequence, out T result) 
    { 
     Console.WriteLine("Test"); 
     result = default(T); 
    } 
} 

從閱讀的答案一對夫婦的其他問題(How to use reflection to call generic Method?Reflection on a static overloaded method using an out parameter),我想我可能能夠調用該方法通過反射如下:

// get the method 
var types = new[] { typeof(IEnumerable<int>), typeof(int).MakeByRefType() }; 
MethodInfo mi = typeof(C).GetMethod(
    "M", BindingFlags.Static, Type.DefaultBinder, types, null); 

// convert it to a generic method 
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) }); 

// call it 
var parameters = new object[] { new[] { 1 }, null }; 
generic.Invoke(null, parameters); 

但是mi是回來空。我試過在types數組中使用object而不是int,但這也不起作用。

如何指定之前調用MakeGenericMethod的通用方法的類型(需要輸出參數)?

+0

您的真實班級是否有'M'超載?如果沒有,你可以使用'GetMethod'變體,你不需要指定參數類型。這並不回答你問的問題。 – hvd

+0

在這種特定情況下,我可以通過不指定任何類型並僅使用名稱來解決該問題,如@SLaks所示。我仍然很想知道指定模板類型數組的語法是什麼,或者它不可能。 –

+0

我出錯的地方是我認爲有必要傳遞類型數組以便使用'out'或'ref'參數。情況並非如此......只要您通過某種方式獲得了正確的'MethodInfo',就可以將它傳遞給參數數組,並且它將設置值。 –

回答

1

我仍然有興趣知道的語法是什麼指定的模板類型的數組,或者如果它是不可能的

I don't think it's possible to pass that kind of detailed type specification to GetMethod[s]。我認爲如果你有多個這樣的M需要查看,你必須把它們全部弄清楚,然後根據MethodInfo的各種屬性和包含的對象進行過濾,例如,在你的特定情況下需要這些對象:

var myMethodM = 
    // Get all the M methods 
    from mi in typeof(C).GetMethods() 
    where mi.Name == "M" 

    // that are generic with one type parameter 
    where mi.IsGenericMethod 
    where mi.GetGenericArguments().Length == 1 
    let methodTypeParameter = mi.GetGenericArguments()[0] 

    // that have two formal parameters 
    let ps = mi.GetParameters() 
    where ps.Length == 2 

    // the first of which is IEnumerable<the method type parameter> 
    where ps[0].ParameterType.IsGenericType 
    where ps[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) 
    where ps[0].ParameterType.GetGenericArguments()[0] == methodTypeParameter 

    // the second of which is ref <the method type parameter> 
    where ps[1].ParameterType.IsByRef 
    where ps[1].ParameterType.GetElementType() == methodTypeParameter 

    select mi; 
3

您已經通過參數M<T>(IEnumerable<int>, ref int)
您需要查找M(IEnumerable<T>, ref T)refout之間的區別僅存在於C#語言中;反射僅具有ref)。

我不知道該怎麼通過;您可能需要遍歷所有方法才能找到它。

在一個不相關的音符,你需要傳遞更多BindingFlags

BindingFlags.Public | BindingFlags.Static 
+0

從你的回答中不清楚,但'ref'和'out'之間的區別不應該在這裏重要,它只是泛型應該重要的。 – hvd

+0

@hvd:是;我忘了提到這一點。 – SLaks

2

這將讓你調用方法:

MethodInfo mi = typeof(C).GetMethod("M"); 
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) }); 
var parameters = new object[] { new[]{1},null}; 
generic.Invoke(null, parameters); 

而且得到了參數:

Console.WriteLine((int)parameters[1]); //will get you 0(default(int)). 
+0

請注意,如果方法過載,這將不起作用。 – SLaks

+0

是SLaks我知道,你的權利一如既往:),我只是提出這個,因爲OP沒有提及除此之外的任何其他方法,我知道它是一個非常「獨特」(大聲笑)的解決方案。 – terrybozzio

1

這是一個衆所周知的問題;要找到該方法,您需要知道其類型參數,但不知道其類型參數而不知道該方法...

一個顯而易見的解決方案是循環遍歷所有方法,直到找到正確的一。

另一種選擇是採取LINQ表達式API的優勢:

public static MethodInfo GetMethod(Expression<Action> expr) 
{ 
    var methodCall = expr.Body as MethodCallExpression; 
    if (methodCall == null) 
     throw new ArgumentException("Expression body must be a method call expression"); 
    return methodCall.Method; 
} 


... 

int dummy; 
MethodInfo mi = GetMethod(() => C.M<int>(null, out dummy)); 
相關問題