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

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

问题描述

我想发出一个返回Func<>的方法。在这个方法里面,我必须创建一个委托或一个lambda表达式,它完全可以提供返回类型。



总的来说应该是这样的:

  //我有一个解决方法,将在我的缺失方法内调用
//这是它的签名:
object Resolve(params object [] args);

//这是我如何使用它:
var barFactory =(Func< IBar>)MissingMethod(typeof(IBar));
var bar = barFactory.Invoke()

//或 - 一个字符串参数:
var fooFactory =(Func< string,IFoo>)MissingMethod(typeof(IFoo),typeof(string));
var foo = fooFactory.Invoke(foo的参数);

MissingMethod()中的内容应如下所示:

  object MissingMethod(键入returnType,params Type [] argTypes)
{
//创建Func的类型基于传递的returnType和argTypes
var funcType = typeof(Func<,...,>)。MakeGenericType(...)

//这里我必须使用Resolve()方法并将lambda转换为正确的类型
return(转换为funcType)((arg1,arg2)=> Resolve(arg1,arg2));
}

我认为获取我的MissingMethod()的唯一方法是使用



你知道有关发布lambda或代理的好资源或教程吗?



做你看到这个问题的另一个可能的解决方案?



编辑:
这是一个我想要的东西的场景: p>

  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> ;(争论); 

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



但是现在我被困在创建这个绑定的Func<,>。并且还可以将它重新编成Func< ,,,>。所以我正在寻找一个能够快速创建我的这个代表的解决方案。他们必须可以按照确切的约束类型进行投放。



编辑: _
我不知道如何描述更好...我正在尝试像这个。但我不想通过目标。而不是

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

我的代理应该看起来像

  delegate void object LateBoundMethod(object [] arguments); 

,目标作为实例字段提供。通过采取和改进马克的解决方案,我得到:

  private Delegate CreateDelegate(键入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;
}

私有readonly容器m_Container;
private类型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); 

我不需要传递null作为第一个参数,我想我需要一个引用this。如何做?

解决方案

第一个问题是 Func< ...> / code>不存在 - 您需要编码为 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);
返回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();
}


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.

Altogether it should look like this:

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

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 ) );
}

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

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

Do you see another possible solution for this problem?

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

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.

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" );

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

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.

EDIT:
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 );

my delegate should look like

delegate void object LateBoundMethod( object[] arguments );

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 );
}

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 );

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

解决方案

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...

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


This works, for example...

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天全站免登陆