¿Por qué Dapper emite código IL en CreateTableConstructor?

.net c# dapper il

Pregunta

Estoy mirando el excelente micro- orbital Dapper, y en el proyecto Dapper.Rainbow , hay algún código que crea un ctor de tabla, usando IL. Esperaba que alguien pudiera explicarme qué está haciendo este código, obviamente está emitiendo código dinámicamente para crear un constructor (o es un código para llamar a un constructor, o ambos), pero ¿qué es lo que realmente se está emitiendo y por qué? es esto necesario?

Aquí está el código

protected Action<TDatabase> CreateTableConstructor(Type tableType)
{
    var dm = new DynamicMethod("ConstructInstances", null, new Type[] { typeof(TDatabase) }, true);
    var il = dm.GetILGenerator();

    var setters = GetType().GetProperties()
        .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == tableType)
        .Select(p => Tuple.Create(
                p.GetSetMethod(true),
                p.PropertyType.GetConstructor(new Type[] { typeof(TDatabase), typeof(string) }),
                p.Name,
                p.DeclaringType
         ));

    foreach (var setter in setters)
    {
        il.Emit(OpCodes.Ldarg_0);
        // [db]

        il.Emit(OpCodes.Ldstr, setter.Item3);
        // [db, likelyname]

        il.Emit(OpCodes.Newobj, setter.Item2);
        // [table]

        var table = il.DeclareLocal(setter.Item2.DeclaringType);
        il.Emit(OpCodes.Stloc, table);
        // []

        il.Emit(OpCodes.Ldarg_0);
        // [db]

        il.Emit(OpCodes.Castclass, setter.Item4);
        // [db cast to container]

        il.Emit(OpCodes.Ldloc, table);
        // [db cast to container, table]

        il.Emit(OpCodes.Callvirt, setter.Item1);
        // []
    }

    il.Emit(OpCodes.Ret);
    return (Action<TDatabase>)dm.CreateDelegate(typeof(Action<TDatabase>));
}

Respuesta aceptada

Básicamente, toma todas las propiedades del tipo actual (que se deriva de la Database<T> de Database<T> ) que se parece a algo así como:

public Table<SomeEntity> SomeTable { get; private set; }

Y crea un delegado que ejecuta código como el siguiente para cada propiedad:

var table = new Table<SomeEntity>(db, "SomeTable");
db.SomeTable = table;


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow