如何发出委托或 lambda 表达式 [英] Howto emit a delegate or lambda expression

查看:22
本文介绍了如何发出委托或 lambda 表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想发出一个返回 Func<> 的方法.在这个方法中,我必须创建一个委托或 lambda 表达式,它正好为返回类型提供服务.

I want to emit a method that returns a Func<>. Inside this method I have to create a delegate or a lambda expression which exactly serves the return type.

它应该看起来像这样:

// I have a resolve method that will be called inside my missing method
// This is it's signature:
object Resolve( params object[] args);

// This is how I use it:
var barFactory = ( Func<IBar> )MissingMethod( typeof( IBar ) );
var bar = barFactory.Invoke();

// or - with one string argument:
var fooFactory = ( Func<string, IFoo> )MissingMethod( typeof( IFoo ), typeof( string ) );
var foo = fooFactory.Invoke( "argument for foo" );

在 MissingMethod() 内部应该是这样的:

Inside the MissingMethod() it should look like:

object MissingMethod( Type returnType, params Type[] argTypes )
{
  // Create the type of Func<> based on the passed returnType and the argTypes
  var funcType = typeof(Func<,...,>).MakeGenericType( ... )

  // Here I have to use the Resolve() method and cast the lambda to the correct type
  return (cast to funcType)( (arg1, arg2) => Resolve( arg1, arg2 ) );
}

我认为获得 MissingMethod() 的唯一方法是使用反射.emit.

I think that the only way to get my MissingMethod() is, to use reflection.emit.

您知道关于发出 lambda 或委托的优秀资源或教程吗?

Do you know good resources or tutorials about emitting a lambda or a delegate?

对于这个问题,您有没有其他可能的解决方案?

Do you see another possible solution for this problem?


这是我想要实现的场景:


Here is a scenario of what I want to achive:

static void Main()
{
  var container = new Container();
  container.Register<Foo>();
  container.Register<ConsumerClass>();

  var consumerClass = Container.Resolve<ConsumerClass>();
}

class Foo()
{
  public Foo( string argument ) {}
}

class ConsumerClass
{
  public ConsumerClass( [Inject] Func<string, Foo> factory )
  {
    var foo1 = factory.Invoke( "first foo" );
    var foo2 = factory.Invoke( "another foo" );
    // ...
  }
}

我正在尝试实现 Container 和 Resolve() 方法.我知道注册了一个Foo"类型.而且我知道它的构造函数需要一个字符串才能被调用.

I am trying to implement the Container and the Resolve() method. I know that there is a "Foo" type registered. And I know that its constructor needs a string to be invoked.

当我必须解析ConsumerClass"类型时,我看到它想要注入一个 Func.这并不是我的容器所能提供的,因为通常它会像这样为 Foo 提供单个实例:

When I have to resolve the type "ConsumerClass" I see that it wants to get a Func injected. That is not exactly what my container can provide, because normally it provides single instaces to Foo like this:

Container.Resolve<Foo>( "argument" );

不过,容器也应该能够提供 Func.它包含所有需要的信息.

But nevertheless the container should be able to provide a Func, too. It has all informations needed.

但是现在我被困在创建这个绑定的 Func<,> 中.请记住,它也可能是 Func<,,,>.因此,我正在寻找一种可以即时创建我的 this 代表的解决方案.它们必须可转换为确切的绑定类型.

But now I am stuck in creating this bound Func<,>. And remeber it could be a Func<,,,>, too. So I am looking for a solution that can create my this delegates on the fly. They have to be castable to the exact bound type.


我不知道如何更好地描述它......我正在尝试做类似 这个.但我不想通过目标.而不是


I am not sure how to describe it better ... I am trying to do something like this. But I do not want to pass a target. Instead of

delegate void object LateBoundMethod( object target, object[] arguments );

我的代表应该看起来像

delegate void object LateBoundMethod( object[] arguments );

并且目标作为实例字段提供.通过采用并改进" Marc 的解决方案,我得到:

and the target is provided as an instance field. By taking and 'improving' the solution of Marc I get:

private Delegate CreateDelegate( Type returnType, Type[] parameterTypes )
{
  m_Type = returnType;

  var i = 0;
  var param = Array.ConvertAll( parameterTypes, arg => Expression.Parameter( arg, "arg" + i++ ) );
  var asObj = Array.ConvertAll( param, p => Expression.Convert( p, typeof( object ) ) );
  var argsArray = Expression.NewArrayInit( typeof( object ), asObj );

  var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );
  var body = Expression.Convert( callEx, returnType );

  var ret = Expression.Lambda( body, param ).Compile();
  return ret;
}

private readonly Container m_Container;
private Type m_Type;

public object Resolve( params object[] args )
{
  return m_Container.Resolve( m_Type, args );
}

但这是不完整的.Resolve() 方法不再是静态的(因为它需要两个实例字段)并且不能被调用.所以这里的问题是

But this is incomplete. The Resolve()-method is not static anymore (because it needs two instance fields) and cannot be called. So the problem here is

var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );

我认为我需要一个对this"的引用,而不是传递 null 作为第一个参数.我该怎么做?

Instead of passing null as the first argument I think I need a reference to 'this'. How do I do that?

推荐答案

第一个问题是 Func<...> 不存在 - 你需要编码到 Func<>, Func<,>, Func<,,>, Func<,,,> 分开.

The first problem is that Func<...> doesn't exist - you'd need to code to Func<>, Func<,>, Func<,,>, Func<,,,> separately.

现在;我了解代码,但我不确定您要解决的情况是什么……您能澄清一下吗?可能有更好的选择...

Now; I understand the code, but I'm not sure what the scenario is that you are trying to solve... can you clarify? There are probably better options...

如果它听起来很复杂,自定义 Expression 可能是最合适的选项(比 Reflection.Emit 简单得多).

If it is as complex as it sounds, a custom Expression is probably the most appropriate option (far simpler than Reflection.Emit).

这有效,例如...

static Delegate MissingFunc(Type result, params Type[] args)
{
    int i = 0;
    var param = Array.ConvertAll(args,
        arg => Expression.Parameter(arg, "arg" + i++));
    var asObj = Array.ConvertAll(param,
        p => Expression.Convert(p, typeof(object)));
    var argsArray = Expression.NewArrayInit(typeof(object), asObj);
    var body = Expression.Convert(Expression.Call(
                null, typeof(Program).GetMethod("Resolve"),
                argsArray), result);
    return Expression.Lambda(body, param).Compile();
}
static void Main()
{
    var func2 = MissingFunc(typeof(string), typeof(int), typeof(float));
}
public static object Resolve( params object[] args) {
    throw new NotImplementedException();
}

这篇关于如何发出委托或 lambda 表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆