2012-10-11 36 views
1

我試圖調用使用Reflection一類的功能(假設對象初始化作爲功能不依賴於被調用)這樣調用成員

/// <summary> 
    /// Calls a static public method. 
    /// Assumes that the method returns a string 
    /// </summary> 
    /// <param name="assemblyName">name of the assembly containing the class in which the method lives.</param> 
    /// <param name="namespaceName">namespace of the class.</param> 
    /// <param name="typeName">name of the class in which the method lives.</param> 
    /// <param name="methodName">name of the method itself.</param> 
    /// <param name="stringParam">parameter passed to the method.</param> 
    /// <returns>the string returned by the called method.</returns> 
    /// 
    public static string InvokeStringMethod5(string assemblyName, string namespaceName, string typeName, string methodName, string stringParam) 
    { 
     //This method was created incase Method has params with default values. If has params will return error and not find function 
     //This method will choice and is the preffered method for invoking 

     // Get the Type for the class 
     Type calledType = Type.GetType(String.Format("{0}.{1},{2}", namespaceName, typeName, assemblyName)); 
     String s = null; 

     // Invoke the method itself. The string returned by the method winds up in s. 
     // Note that stringParam is passed via the last parameter of InvokeMember, as an array of Objects. 

     if (MethodHasParams(assemblyName, namespaceName, typeName, methodName)) 
     { 
      s = (String)calledType.InvokeMember(
         methodName, 
         BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, 
         null, 
         null, 
         new Object[] { stringParam }); 
     } 
     else 
     { 
      s = (String)calledType.InvokeMember(
      methodName, 
      BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, 
      null, 
      null, 
      null); 
     } 

     // Return the string that was returned by the called method. 
     return s; 

    } 

    public static bool MethodHasParams(string assemblyName, string namespaceName, string typeName, string methodName) 
    { 
     bool HasParams; 
     string name = String.Format("{0}.{1},{2}", namespaceName, typeName, assemblyName); 
     Type calledType = Type.GetType(name); 
     MethodInfo methodInfo = calledType.GetMethod(methodName); 
     ParameterInfo[] parameters = methodInfo.GetParameters(); 

     if (parameters.Length > 0) 
     { 
      HasParams = true; 
     } 
     else 
     { 
      HasParams = false; 
     } 

     return HasParams; 

    } 

這是取自here

有沒有其他的/更好的方法來做到這一點?

這個活動可以是通用的嗎?與使用Dynamic類似,可以在.Net 4.0中調用Non-Static methods,以便返回類型可以獨立。

我從來沒有在實際場景中使用dynamic關鍵字(只讀一些例子)來actul使用還是未知數我

在這方面的任何幫助/方向,將不勝感激 感謝

+0

爲了能有你的方法返回任何類型,要麼返回'object'(這是反射庫中大多數方法已經做到的),要麼使用泛型方法。 –

+0

@ C.Evenhuis將泛型和反射結合起來通常不會有用 –

+0

@MarcGravell我並不是說應該使用反射來調用泛型方法,而只是在將結果傳遞給調用方之前將結果轉換爲所需類型。我的印象是,「動態」和「通用」這兩個術語在這個問題上混在一起。 –

回答

1

回答您查詢在dynamic;不,這在這裏不太合適。 dynamic在成員名稱(或操作)在編譯時已知但不可證明存在的情況下非常有用 - 基本上,是鴨子鍵入。例如:

dynamic foo = GetSomeRandomObject(); 
foo.ThisShouldExist("abc"); 

這樣做的事情相似,但用法不同。所以是的,你留下了反思。你在做什麼是非常正確的。我唯一可能改變的將是獲得MethodInfo,並從那裏開始工作 - 但如果您可以將API更改爲接受單個string assemblyQualifiedName,那將更加方便和靈活。但也許:

public static string InvokeStringMethod5(string assemblyName, 
    string namespaceName, string typeName, string methodName, string stringParam) 
{ 
    string assemblyQualifiedName = string.Format("{0}.{1},{2}", 
     namespaceName, typeName, assemblyName); 
    Type calledType = Type.GetType(assemblyQualifiedName); 
    if(calledType == null) throw new InvalidOperationException(
     assemblyQualifiedName + " not found"); 
    MethodInfo method = calledType.GetMethod(methodName, 
     BindingFlags.Public | BindingFlags.Static); 
    switch (method.GetParameters().Length) 
    { 
     case 0: 
      return (string)method.Invoke(null, null); 
     case 1: 
      return (string)method.Invoke(null, new object[] { stringParam }); 
     default: 
      throw new NotSupportedException(methodName 
       + " must have 0 or 1 parameter only"); 
    } 
} 
+0

@Mark Gravell此功能是否適用於非靜態/公共功能? 另外,如果返回類型保持爲對象如何將其轉換爲其所需的類型? – Ankesh

+0

@ adcool2007對於非靜態函數,您需要將'BindingFlags'更改爲包含'Instance',並且需要包含一個非null對象作爲第一個參數給'Invoke',但基本上* ,是的,相同的代碼將適用於非靜態方法。對於「將其轉換爲所需類型」 - 這取決於上下文。我返回字符串,因爲這是你的例子。你可以說得更詳細點嗎? –

1

爲了回答關於如何將結果轉換到一個通用的返回類型的問題,該方法看起來是這樣的:

public static T InvokeMethod<T>(string assemblyName, string namespaceName, string typeName, string methodName, string stringParam) 
{ 
    // instead of String s = null; 
    T methodResult = default(T); 

    // instead of s = (String)calledType.InvokeMember(...) 
    methodResult = (T)calledType.InvokeMember(...); 

    // return s; 
    return methodResult; 
} 
+0

它可以工作,但實際上'int i = InvokeMethod (...)'與'int i =(int)InvokeMethod(...)'之間沒有太大差別。我們所改變的只是尖括號*。 –