如何发出委托或lambda表达式

3
我希望能够发出一个返回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()的唯一方法是使用reflection.emit。

你知道有关发出lambda或delegate的好资源或教程吗?

您是否看到此问题的另一个可能解决方案?

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

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" );
    // ...
  }
}

我正在尝试实现容器和Resolve()方法。我知道已经注册了“Foo”类型。我知道它的构造函数需要一个字符串来调用。

当我需要解析类型“ConsumerClass”时,我发现它想要注入一个Func。这不是我的容器可以提供的,因为通常它会像这样提供单个实例到Foo:

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

然而,容器也应该能够提供一个 Func。它拥有所有所需的信息。

但现在我卡在了创建这个绑定的 Func<,> 上。请记住它也可能是一个 Func<,,,>。因此,我正在寻找一种可以动态创建我的委托的解决方案。它们必须能够强制转换为确切的绑定类型。

编辑:
我不确定如何更好地描述它... 我正在尝试做类似于这样的事情。但我不想传递一个目标。

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作为第一个参数传递。 我该怎么做?


1
我必须说我并不完全确定你想要做什么,但是将MissingMethod方法泛型化会让你解决问题的一半,这不是一个选项吗? - kastermester
哦,我也明白你必须编写多次以覆盖所有可能的 Func<> 泛型,但正如 Marc 所提到的,你无论如何都必须硬编码它。 - kastermester
通过编辑,我仍然不明白规则是什么...你会在[Inject]注入什么?为什么? - Marc Gravell
1个回答

7
第一个问题是 Func<...> 不存在 - 需要分别编写 Func<>, Func<,>, Func<,,>, Func<,,,> 的代码。
我理解这段代码,但不确定你想解决的场景是什么……能否说明一下?可能有更好的选择……
如果它像听起来那样复杂,自定义 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容器创建更多一个类型的实例。 - tanascius
谢谢...我对表达式还不熟悉。你能给我一个提示,如何将Resolve()变成一个带有签名"object Resolve(Type, params object)"的实例方法吗?我还是卡住了 :/ - tanascius
抱歉,我必须赶火车离开;我可以详细介绍这个领域,但首先我要重复我的问题:在这里的情况是什么?我可以用至少3种方法来处理这个问题(而且没有一种是Reflection.Emit)...如果它是一个“实例”方法...它是一个实例“的”,对吗?也许你可以展示一些半成品。如果你对事情还不确定,随时取消标记这个作为答案 - 我不会生气的。只有当你确信问题已解决时才将其标记为完成(我不确定是否解决了...) - Marc Gravell
我接受了你的答案,因为我相信它对我很有用 :) 我只需要找出如何使用表达式调用一个实例方法 "object Resolve(Type, params object)"。我编辑了我的帖子 - 希望它能澄清我想做什么... - tanascius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接