Как скомпилировать лямбда-выражение в динамически создаваемый класс - PullRequest
0 голосов
/ 03 января 2019

Я пытаюсь создать расширение класса, используя отражение emit.

И это вроде работает.

var extendwith = new List<Type>();
extendwith.Add(typeof(object));
var t = Utils.DynamicInherit<BaseTest>("Extended",typeof(UtilsTest).GetMethod(nameof(Testing)), extendwith);

var instance = Activator.CreateInstance(t, new TestClass(), new { A=1 });


public class BaseTest
{
    public readonly TestClass testClass;

    public object IsNotNull;

    public BaseTest(TestClass testClass)
    {
        this.testClass = testClass;
    }
}

public static void Testing(BaseTest baseTest, List<object> objects)
    {
        foreach(var t in objects)
        {
            baseTest.IsNotNull = t;
        }
    }

Что здесь происходит, так это то, что тип (t), возвращаемый методом DynamicInherit, теперь будет наследоваться от класса BaseTest и иметь конструктор, содержащий 2 параметра (TestClass, Object)

Статический метод Testing будет вызываться внутри конструктора «сконструированного типа». Он вызывается с использованием этого кода IL.

constructorBuilder.Emit(OpCodes.Ldarg_0); //The this a referance to the created base class
constructorBuilder.Emit(OpCodes.Ldloc_0); //Reference to a List<Objects> that is passed in thorugh the constructor
constructorBuilder.Emit(OpCodes.Call, constructor); //The function to be called.. in this case the "public static void Testing(BaseTest baseTest, List<object> objects)"

Это работает "как ожидалось", но я бы хотел изменить его на использование выражения lamda вместо статической функции.

var t = Utils.DynamicInherit<BaseTest>("Extended",(baseO, objects) => {foreach(var t in objects)
        {
            baseTest.IsNotNull = t;
        }} , 
        extendwith);

Я знаю, что должен изменить строку

constructorBuilder.Emit(OpCodes.Call, constructor); 

Но я не могу понять, как .... Любые предложения ???

1 Ответ

0 голосов
/ 04 января 2019

С учетом

Action<BaseText,List<object>> f = (BaseTest baseO, List<object> objects) => {
    foreach(var t in objects) {
        baseTest.IsNotNull = t;
    }
};

Тогда f.Method должно быть то, что вам нужно, я думаю:

var t = Utils.DynamicInherit<BaseTest>("Extended",f.Method, extendwith);

Кроме того, вы можете объединить все это:

var t = Utils.DynamicInherit<BaseTest>("Extended",((Action<BaseTest,List<object>>)((baseO, objects) => {foreach(var t in objects)
    {
        baseTest.IsNotNull = t;
    }})).Method,
    extendwith);

Использование имеющегося у меня служебного класса немного облегчает чтение:

public static class To {
    public static Func<TResult> Func<TResult>(Func<TResult> func) => func;
    public static Func<T, TResult> Func<T, TResult>(Func<T, TResult> func) => func;
    public static Func<T1, T2, TResult> Func<T1, T2, TResult>(Func<T1, T2, TResult> func) => func;
    public static Func<T1, T2, T3, TResult> Func<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func) => func;
    public static Func<T1, T2, T3, T4, TResult> Func<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func) => func;
    public static Func<T1, T2, T3, T4, T5, TResult> Func<T1, T2, T3, T4, T5, TResult>(Func<T1, T2, T3, T4, T5, TResult> func) => func;
    public static Func<T1, T2, T3, T4, T5, T6, TResult> Func<T1, T2, T3, T4, T5, T6, TResult>(Func<T1, T2, T3, T4, T5, T6, TResult> func) => func;
    public static Func<T1, T2, T3, T4, T5, T6, T7, TResult> Func<T1, T2, T3, T4, T5, T6, T7, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TResult> func) => func;
    public static Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> func) => func;
    public static Action<T> Action<T>(Action<T> act) => act;
    public static Action<T1, T2> Action<T1, T2>(Action<T1, T2> act) => act;
    public static Action<T1, T2, T3> Action<T1, T2, T3>(Action<T1, T2, T3> act) => act;
    public static Action<T1, T2, T3, T4> Action<T1, T2, T3, T4>(Action<T1, T2, T3, T4> act) => act;
    public static Action<T1, T2, T3, T4, T5> Action<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> act) => act;
    public static Action<T1, T2, T3, T4, T5, T6> Action<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> act) => act;
    public static Action<T1, T2, T3, T4, T5, T6, T7> Action<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> act) => act;
    public static Action<T1, T2, T3, T4, T5, T6, T7, T8> Action<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> act) => act;
}

Тогда у вас просто есть:

var t = Utils.DynamicInherit<BaseTest>("Extended", To.Action((baseO, objects) => {
    foreach(var t in objects) {
        baseTest.IsNotNull = t;
    }}).Method,
    extendwith);
...