Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create delegate of getter with changed return type

Tags:

c#

.net

I need to map all of properties to Func. How would I do that?

I've got class

class A 
{
    public int SomeIntValue { get; }
    public string SomeStringValue { get; }
    public Dictionary<...> SomeDictionary { get; }
}

and dictionary Dictionary<string, Func<A, object>>. I'm trying to create delegate for the getter methods but I can't really figure out how to do it.

In such a way, it doesn't work and it make sense why. I need to do it indirectly but how?

(Func<TType, object>) Delegate.CreateDelegate(typeof(Func<TType, object>), null, property.GetGetMethod())
like image 576
Puchacz Avatar asked Sep 06 '25 14:09

Puchacz


2 Answers

The issue you've got is that converting from a Func<A, int> to Func<A, object> is not a representation preserving conversion, so it is not allowed via the variance modifiers provided on the declaration of the Func family of delegates. For value types, you need an extra IL instruction to be added which is a boxing conversion. Below I give a solution that generates a dynamic method to add the required instruction when necessary (i.e. when the return value is a value type). It is also more efficient because it directly invokes the property rather than relying on reflection to handle the invocation.

using System.Reflection.Emit;

public static Dictionary<string, Func<T, object>> GetGetMethods<T>()
{
    var getMethods = new Dictionary<string, Func<T, object>>();
    foreach (var prop in typeof(T).GetProperties())
    {    
        Func<T, object> del;
        if (prop.PropertyType.IsValueType)
        {
            var dynMethod = new DynamicMethod(string.Format("Dynamic_Get_{0}_{1}", typeof(T).Name, prop.Name), typeof(object), new[] { typeof(T) }, typeof(T).Module);
            var ilGen = dynMethod.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Callvirt, prop.GetGetMethod());
            ilGen.Emit(OpCodes.Box, prop.PropertyType);
            ilGen.Emit(OpCodes.Ret);

            del = (Func<T, object>)dynMethod.CreateDelegate(typeof(Func<T, object>));
        }
        else
        {
            del = (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), null, prop.GetGetMethod());
        }

        getMethods[prop.Name] = del;
    }

    return getMethods;
}
like image 104
Mike Zboray Avatar answered Sep 08 '25 05:09

Mike Zboray


I guess you can create the delegate by using the method group somePropertyInfo.GetValue:

Func<A, object> del = somePropertyInfo.GetValue;

And then you can put that into the dictionary.

You don't need the GetGetMethod call because GetValue will call the getter. That method is for getting the property as a MethodInfo object. Here, you don't need a MethodInfo.

like image 38
Sweeper Avatar answered Sep 08 '25 04:09

Sweeper