如何使用反射来获取对泛型类型的扩展方法 [英] How to use reflection to get extension method on generic type

查看:183
本文介绍了如何使用反射来获取对泛型类型的扩展方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从上德interwebs我已经收集到这下面的函数各种来源:

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");



当我尝试使用反射从另一个泛型函数的上下文中调用它发生我的问题。 SO充满描述如何得到通用的方法和静态方法的MethodInfo的答案,但我似乎不能以正确的方式把这些结合在一起。结果
我已经正确地确定传递泛型类型本身就是一个泛型类型(可空<> ),现在我想使用反射来调用 TryParseNullable 扩展方法在可空<>

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]
    }
}

有人可以把我从我的痛苦?结果
中的的typeof(T)收益正确类型的信息,我想,也许我用它一点点错误与实现getMethod()呼叫,或者我还没有指定的调用正确的参数实现getMethod()

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().

<分> 1。 链接引用乔恩斯基特答案

推荐答案

的问题是,扩展方法不修改他们是'扩展'的类型。实际发生的幕后是编译器透明地将所有的,似乎是在问题调用静态方法的对象上发出的呼吁。

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.

int? input = new int?().TryParseNullable("12345");
// becomes...
int? input = YourClass.TryParseNullable(new int?(), "12345");



从那里,为什么它没有显示通过反射了它变得明显。这也解释了为什么你必须有,其中 YourClass 是扩展方法是定义的命名空间的使用指令可见的编译器。至于如何你可以在该信息实际上得到的,我不知道还有一个办法,总之在所有类型的声明运行(也许是有趣类的过滤列表,如果你知道那种在编译时的信息)找对于与上定义,然后试图解析 ExtensionMethodAttribute [ExtensionMethod] )的<$ C $静态方法C> MethodInfo的的参数列表的工作,如果他们对可空<工作;方式>

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 where YourClass 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 the ExtensionMethodAttribute ([ExtensionMethod]) defined on them, then trying to parse the MethodInfo for the parameter list to work out if they work on Nullable<>.

这篇关于如何使用反射来获取对泛型类型的扩展方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆