Dynamic Func <> para el mapa de consulta Dapper

c# dapper reflection

Pregunta

Intento generar y ejecutar dinámicamente el sql para Dapper con el objetivo de pasar simplemente un tipo y el sql se genera y ejecuta dinámicamente.

Clases de ejemplo:

public class User
{
    [Key]
    public int UserId { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    [Key]
    public int UserId { get; set; }
    public string PostCode { get; set; }
}

Efectivamente ejecutará lo siguiente:

// sql: "SELECT User.UserId, Address.UserId, Address.PostCode FROM User LEFT JOIN Address ON Address.User = User.UserId"... // auto generated from 'User' type including join to 'Address';

connection.Query<User, Address, User>(sql, /*** map argument needs to be dynamic Func<> ***/);

Entonces, dados estos tipos de User y Address que solo se conocen en el tiempo de ejecución, ¿cómo puedo generar el delegado delegado Func<User, Address, User> para pasar al argumento del map ?

Func<User, Address, User> map = (u, a) => {
    u.Address = a;
    return u;
}

Los ejemplos que he visto para crear un Func<> usando reflexión asumen que los tipos son conocidos, en mi caso no son así, los argumentos de tipo varían (Func <,> / Func <,,> / Func <,,,> etc. )

Cualquier ayuda apreciada. Seguiré trabajando con ejemplos usando expresiones para ver si hay algo.

Respuesta popular

Esto es lo más cerca que he llegado. Traté de clonar el repositorio de Dapper para investigar cómo funciona el método Query (), pero estoy usando una versión anterior de Visual Studio.

public static class DynamicFuncHelper
{
    public static Delegate CreateFunc(Type type1, Type type2)
    {
        Type funcType = typeof(Func<,,>).MakeGenericType(type1, type2, type1);
        MethodInfo method =
            typeof(DynamicFuncHelper<,>)
            .MakeGenericType(type1, type2)
            .GetMethod("SetAddressProperty",
                BindingFlags.Public | BindingFlags.Static
            );
        return Delegate.CreateDelegate(funcType, method);
    }
}

public static class DynamicFuncHelper<T,U> 
    where T : class 
    where U : class
{
    public static T SetAddressProperty(T obj1, U obj2)
    {
        obj1.GetType().InvokeMember("Address",
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
            Type.DefaultBinder, obj1, new[] { obj2 });
        return obj1;
    }
}

Pasó esta prueba unitaria

[TestClass]
public class DynamicFuncTest
{
    [TestMethod]
    public void TestDynamicMapper()
    {
        var actualUser = new User { UserId = 1 };
        var actualAddress = new Address { PostCode = "12345", UserId = 1 };
        var testSetAddress = DynamicFuncHelper.CreateFunc(typeof(User), typeof(Address));
        var delegateResult = testSetAddress.DynamicInvoke(actualUser, actualAddress);
        Assert.AreEqual(actualUser, delegateResult, "Delegate result was not actualUser");
        Assert.AreEqual(actualAddress, actualUser.Address, "User address was not expected address");
    }
}


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué