【问题标题】:Howto emit a delegate or lambda expression如何发出委托或 lambda 表达式
【发布时间】:2010-10-30 17:03:03
【问题描述】:

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

它应该看起来像这样:

// 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() 内部应该是这样的:

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。

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

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

编辑:
这是我想要实现的场景:

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”类型。而且我知道它的构造函数需要一个字符串才能被调用。

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

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

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

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

编辑:
我不知道如何更好地描述它......我正在尝试做类似this 的事情。但我不想通过目标。而不是

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

我的代表应该看起来像

delegate void object LateBoundMethod( object[] arguments );

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

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() 方法不再是静态的(因为它需要两个实例字段)并且不能被调用。所以这里的问题是

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

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

【问题讨论】:

  • 我得说我不是 100% 确定我得到了你想要做的事情,但是让 MissingMethod 方法通用不会让你解决问题的一半吗?或者这不是一个选择?
  • 哦,另外,我确实知道您必须对其进行多次编码才能涵盖所有可能的 Func 泛型,但正如 Marc 所提到的,无论如何您都必须对其进行硬编码.
  • 通过编辑,我仍然不明白规则是什么......你会让它在[Inject]注入什么?为什么?

标签: c# delegates lambda reflection.emit


【解决方案1】:

第一个问题是 Func&lt;...&gt; 不存在 - 您需要分别编码为 Func&lt;&gt;Func&lt;,&gt;Func&lt;,,&gt;Func&lt;,,,&gt;

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

如果它听起来很复杂,那么自定义 Expression 可能是最合适的选择(比 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();
}

【讨论】:

  • 感谢您的回复。你是对的 Func<...> - 我必须将接受的参数限制为四个。我想将我的代码与 Resolve() 方法(由 IoC 容器提供)分离。相反,我希望能够创建小工厂(作为 Func 参数传递),使对象能够通过间接使用 IoC 容器来创建一种类型的更多实例。
  • 谢谢...我是 Expressions 的新手。您能否给我一个提示,如何使 Resolve() 成为具有签名“object Resolve(Type, params object)”的实例方法?我仍然卡住了:/
  • 对不起,我得去坐火车了;我可以高度详细地阐述这个领域——但首先我要重复我的问题:这里的情况是什么?我可以通过至少 3 种方式来解决这个问题(它们都不是 Reflection.Emit)......如果它是一个 instance 方法......它是什么实例 of?也许你可以表现得更半完整。如果您还不确定,请随时取消将其标记为答案 - 我不会被冒犯。仅当您对问题已解决感到高兴时才将其标记为完成(我不确定它是否......)
  • 我接受了你的回答,因为我确信它为我提供了有用的信息:) 我只需要了解如何使用表达式调用实例方法“object Resolve(Type, params object)”。我编辑了我的帖子 - 希望它能阐明我想要做什么......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 2023-03-14
相关资源
最近更新 更多