如何发出委托或lambda表达式

tan*_*ius 3 c# lambda delegates reflection.emit

我想发出一个返回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" );
Run Code Online (Sandbox Code Playgroud)

在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 ) );
}
Run Code Online (Sandbox Code Playgroud)

我认为获取MissingMethod()的唯一方法是使用reflection.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" );
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

当我必须解决类型"ConsumerClass"时,我发现它想要注入一个Func.这不是我的容器可以提供的,因为通常它为Foo提供单一的实例,如下所示:

Container.Resolve<Foo>( "argument" );
Run Code Online (Sandbox Code Playgroud)

但是容器应该也能够提供Func.它有所需的所有信息.

但是现在我被困在创建这个绑定的Func <,>.并记住它也可能是一个Func <,,,>.所以我正在寻找一种可以动态创建我的代表的解决方案.它们必须可浇铸到精确的绑定类型.

编辑:
我不知道该怎么形容好...我试图做类似这样.但我不想传递目标.代替

delegate void object LateBoundMethod( object target, object[] arguments );
Run Code Online (Sandbox Code Playgroud)

我的代表应该是这样的

delegate void object LateBoundMethod( object[] arguments );
Run Code Online (Sandbox Code Playgroud)

并且目标作为实例字段提供.通过采取并"改进"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 );
}
Run Code Online (Sandbox Code Playgroud)

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

var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ell 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();
}
Run Code Online (Sandbox Code Playgroud)