從各種渠道對德interwebs我已經收集到這個如下功能:如何使用反射來獲取擴展方法上泛型類型
public static Nullable<T> TryParseNullable<T>(this Nullable<T> t, string input) where T : struct
{
if (string.IsNullOrEmpty(input))
return default(T);
Nullable<T> result = new Nullable<T>();
try
{
IConvertible convertibleString = (IConvertible)input;
result = new Nullable<T>((T)convertibleString.ToType(typeof(T), CultureInfo.CurrentCulture));
}
catch (InvalidCastException) { }
catch (FormatException) { }
return result;
}
我已經把它做成一個擴展方法,它工作得很好如果我直接打電話給我:
int? input = new int?().TryParseNullable("12345");
我嘗試使用另一個通用函數的上下文中的反射來調用它時出現問題。 SO中有很多描述如何獲得泛型方法和靜態方法的MethodInfo的答案,但我似乎無法以正確的方式將它們組合在一起。
我已經正確地確定傳遞泛型類型本身是一個通用型(Nullable<>
),現在我想使用反射來呼籲Nullable<>
的TryParseNullable
擴展方法:
public static T GetValue<T>(string name, T defaultValue)
{
string result = getSomeStringValue(name);
if (string.IsNullOrEmpty(result)) return defaultValue;
try
{
if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>))
{
MethodInfo methodInfo;
//using the TryParse() of the underlying type works but isn't exactly the way i want to do it
//-------------------------------------------------------------------------------------------
NullableConverter nc = new NullableConverter(typeof(T));
Type t = nc.UnderlyingType;
methodInfo = t.GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new[] { typeof(string), t.MakeByRefType() }, null);
if (methodInfo != null)
{
var inputParameters = new object[] { result, null };
methodInfo.Invoke(null, inputParameters);
return (T) inputParameters[1];
}
//start of the problem area
//-------------------------
Type ttype = typeof(T);
//this works but is undesirable (due to reference to class containing the static method):
methodInfo = typeof(ParentExtensionsClass).GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//standard way of getting static method, doesn't work (GetMethod() returns null):
methodInfo = ttype.GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//Jon Skeet's advised method, doesn't work in this case (again GetMethod() returns null):
//(see footnote for link to this answer)
methodInfo = ttype.GetMethod("TryParseNullable");
methodInfo = methodInfo.MakeGenericMethod(ttype);
if (methodInfo != null)
Console.WriteLine(methodInfo);
//another random attempt (also doesn't work):
methodInfo = ttype.GetMethod("TryParseNullable", BindingFlags.Public | BindingFlags.Static, Type.DefaultBinder, new[] { typeof(string) }, null);
if (methodInfo != null)
Console.WriteLine(methodInfo);
}
// if we get this far, then we are not handling the type yet
throw new ArgumentException("The type " + defaultValue.GetType() + " is not yet supported by GetValue<T>.", "T");
}
catch (Exception e)
{
[snip]
}
}
有人可以把我出來我的痛苦?
typeof(T)
返回正確的類型信息,我認爲我可能在調用GetMethod()
時錯誤地使用了它,或者我沒有通過調用GetMethod()
來指定正確的參數。
1. Link to referenced Jon Skeet answer
你確定擴展方法被認爲是typeof(T)的一部分嗎?我的猜測是你需要從實現擴展方法的靜態類中獲取方法。你是否嘗試過調用GetMethods()並檢查返回的內容? – dlev 2011-05-11 04:28:14
謝謝@dlev,那就是答案。擴展方法的真正基本原理之一,我忽略了它。 – slugster 2011-05-11 04:43:14
只是關於你的邏輯的一個註釋,如果'input == null'爲什麼要返回'default(T)'作爲'T?'?看起來像'更正確的'邏輯將返回null。 – 2011-05-11 05:08:22