简体   繁体   中英

Issue with delegate return type

Have following code

public delegate object ParseHandler(string s);
public static ParseHandler GetParser(Type t)
{
    MethodInfo parse = t.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
        null, new Type[] { typeof(string) }, null);

    if (parse != null)
        return (ParseHandler)Delegate.CreateDelegate(typeof(ParseHandler), parse, true);

    return null;
}

is blowing up on the Delegate.CreateDelegate() call with "Error binding to target method." apparently because ParseHandler is defined as returning object instead of type specific return value.

I don't know type at the compile type, so I can't replace type parameter with generic (and if I did then the whole function would not be needed).

A bit confused on how to deal with this. The required behavior is to find public static Parse(string) method for given type and create a delegate for it to be called later.

It should be fine so long as the real return value is a reference type - but it makes sense for this to fail for a value type return value. (See Eric Lippert's post about representation and identity for more detailed explanations.)

One option is to create a generic class like this:

public class BoxingParserDelegate<T>
{
    private readonly Converter<string, T> parser;

    public BoxingParserDelegate(Converter<string, T> parser)
    {
        this.parser = parser;
    }

    public object Parse(string x)
    {
        return parser(x);
    }
}

In your GetParser method, you'd check whether the return type of parse is a value type, and if so create an instance of BoxingParserDelegate<T> via reflection. You can then create the ParseHandler instance from the Parse method of the BoxingParserDelegate .

This will all be frankly somewhat awkward, but should work. It feels like there should be a simpler approach, to be honest.

(On .NET 3.5 or higher I'd recommend using expression trees, but I've only just seen the .NET 2.0 tag.)

EDIT: Aha, have thought of slightly simpler approach:

public static ParseHandler BuildParseHandler<T>(Converter<string, T> converter)
{
    // Performs boxing automatically
    return delegate(string x) { return converter(x); }
}

This is effectively asking the compiler to do half of the above work for you. Then you just need to work out whether you need to call this, and do so with reflection if necessary. Something like this:

public static ParseHandler GetParser(Type t)
{
    MethodInfo parse = t.GetMethod("Parse",
        BindingFlags.Static | BindingFlags.Public,
        null, new Type[] { typeof(string) }, null);

    // Method not found
    if (parse == null)
    {
        return null;
    }

    // Reference type - use delegate covariance
    if (!parse.ReturnType.IsValueType)
    {
        return (ParseHandler) Delegate.CreateDelegate(typeof(ParseHandler),
            parse, true);
    }

    // Tricky situation: call BuildParseHandler with generics
    Type delegateType = typeof(Converter<,>).MakeGenericType(typeof(string),
                                                             parse.ReturnType);
    object converter = Delegate.CreateDelegate(delegateType, parse, true);

    // You may need extra work to get this... let me know whether or not it works.
    // Obviously if you make it private, you'll need extra binding flags.
    MethodInfo method = typeof(TypeContainingThisMethod)
                            .GetMethod("BuildParseHandler");
    method = method.MakeGenericMethod(parse.ReturnType);

    return (ParseHandler) method.Invoke(null, new object[] { converter });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM