如何使用反射来获取泛型类型的扩展方法
从互联网上的各种来源中,我收集到了以下函数:
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<>
),现在我想使用反射来调用 TryParseNullable
扩展方法Nullable<>
:
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。 引用的 Jon Skeet 答案的链接
From various sources on teh interwebs I've gleaned this following function:
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;
}
I've made it into an extension method, and it works just fine if I call it directly:
int? input = new int?().TryParseNullable("12345");
My problem occurs when I try to call it using reflection from within the context of another generic function. SO is full of answers describing how to get the MethodInfo of generic methods and static methods, but I can't seem to put these together in the right way.
I've correctly determined that the passed generic type is itself a generic type (Nullable<>
), now I want to use reflection to call the TryParseNullable
extension method on the Nullable<>
:
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]
}
}
Can someone put me out of my misery?
The typeof(T)
returns the correct type info, I figure that maybe I'm using it a little incorrectly with the GetMethod()
call, or I haven't specified the right parameters with the call to GetMethod()
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于扩展方法不会修改它们“扩展”的类型。幕后实际发生的事情是,编译器透明地将所有似乎对相关对象进行的调用转换为对静态方法的调用。
IE。
从那里开始,为什么它没有通过反射显示出来就变得很明显了。这也解释了为什么您必须为定义
YourClass
的命名空间使用using
指令,以使扩展方法对编译器可见。至于如何实际获取这些信息,我不确定是否有一种方法,不需要运行所有声明的类型(也许是有趣的类的过滤列表,如果您在编译时知道此类信息)对于定义了ExtensionMethodAttribute
([ExtensionMethod]
) 的静态方法,然后尝试解析参数列表的MethodInfo
来计算是否他们致力于可为空
。The problem is that extension methods don't modify the type they are 'extending'. What actually happens behind the scenes is that the compiler transparently translates all the calls that seem to be made on the object in question to calls to your static method.
ie.
From there it becomes obvious why it's not showing up via reflection. This also explains why you have to have a
using
directive for the namespace whereYourClass
is defined for the extension methods to be visible to the compiler. As to how you can actually get at that information, I'm not sure there is a way, short of running over all the declared types (perhaps a filtered list of interesting classes, if you know that sort of information at compile time) looking for static methods with theExtensionMethodAttribute
([ExtensionMethod]
) defined on them, then trying to parse theMethodInfo
for the parameter list to work out if they work onNullable<>
.