代码发射和表达

时间:2014-10-17 08:34:50

标签: c# lambda

我正在使用Code Emit进行动态代码生成。 我想使用外部工厂方法设置一个字段。 这是我的(简化)代码:

定义:

    Func<object> fact = () => new B();
    var mi = fact.GetMethodInfo();
    var t = typeof(B);

发射代码:

    ILGenerator ilg;
    var tb = _mb.DefineType("myProxy", TypeAttributes.Public | TypeAttributes.Class, typeof(object));
    var fieldBuilder = tb.DefineField("proxy", t, FieldAttributes.Private);
    var ctorBuilder = tb.DefineConstructor(...);

    ilg = ctorBuilder.GetILGenerator();

    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
    ilg.Emit(OpCodes.Ldarg_0);
    ilg.Emit(OpCodes.Callvirt, mi);
    ilg.Emit(OpCodes.Castclass, t);
    ilg.Emit(OpCodes.Stfld, fieldBuilder);
    ilg.Emit(OpCodes.Ret);

创建一个实例:

Activator.CreateInstance(tb.CreateType());
抛出

TargetInvocationException

  

{“找不到方法:\”?\“。”}

以下是我期待的结果:

public class A
{
    private B _proxy;
    public A(Func<object> factory)
    {
        _proxy = (B)factory();
    }
}

但是工厂方法是固定的,不作为参数提供......

public class A
{
    private B _proxy;
    public A()
    {
        _proxy = (B) //[GENERATE ME] () => new B();
    }
}

任何建议?

1 个答案:

答案 0 :(得分:0)

你必须通过&#34; Invoke&#34;来调用委托。方法,但您需要将工厂代理提供给您的代理。您可以向代理构造函数添加参数。

public class B
{
}

static internal class Metadata<T> //Avoid lock & string metadata description
{
    static public readonly Type Type = typeof(T);

    static public FieldInfo Field<X>(Expression<Func<T, X>> expression)
    {
        return (expression.Body as MemberExpression).Member as FieldInfo;
    }

    static public PropertyInfo Property<X>(Expression<Func<T, X>> expression)
    {
        return (expression.Body as MemberExpression).Member as PropertyInfo;
    }

    static public MethodInfo Method(Expression<Action<T>> expression)
    {
        return (expression.Body as MethodCallExpression).Method;
    }

    static public MethodInfo Method<X>(Expression<Func<T, X>> expression)
    {
        return (expression.Body as MethodCallExpression).Method;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var _Factory = new Func<object>(() => new B());

        TypeBuilder _TypeBuilder = null;// = ...;
        var _Parameters = new Type[] { Metadata<Func<object>>.Type };
        var _Constructor = _TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, _Parameters);
        var _Body = _Constructor.GetILGenerator();
        //...
        _Body.Emit(OpCodes.Ldarg_1);
        _Body.Emit(OpCodes.Call, Metadata<Func<object>>.Method(_Func => _Func.Invoke()));
        //...

        var _Type = _TypeBuilder.CreateType();
        var _Parameter = Expression.Parameter(Metadata<Func<object>>.Type);
        var _New = Expression.Lambda<Func<Func<object>, object>>(Expression.New(_Type.GetConstructor(_Parameters), _Parameter), _Parameter).Compile();

        var _Instance = _New(_Factory);
    }
}