作为委托的构造函数 - 它可能在C#中吗?

aka*_*vel 57 c# constructor delegates

我有一个类如下:

class Foo
{
  public Foo(int x) { ... }
}
Run Code Online (Sandbox Code Playgroud)

我需要传递一个像这样的委托的方法:

delegate Foo FooGenerator(int x);
Run Code Online (Sandbox Code Playgroud)

是否可以直接将构造函数作为FooGenerator值传递,而无需键入:

delegate(int x) { return new Foo(x); }
Run Code Online (Sandbox Code Playgroud)

编辑:对于我个人使用,问题涉及.NET 2.0,但欢迎3.0 +的提示/响应.

Mar*_*ell 55

我假设你通常会做这样的事情作为工厂实现的一部分,其中实际的类型在编译时是不知道的...

首先,请注意,更简单的方法可能是创建后的初始化步骤,然后您可以使用泛型:

static T Create<T>({args}) where T : class, ISomeInitInterface, new() {
    T t = new T();
    t.Init(args);
    return t;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用MakeGenericMethod和/或CreateDelegate.


除此以外; 您可以使用Expression(3.5)或DynamicMethod(2.0)动态执行此操作.

Expression方法更容易编码:

    var param = Expression.Parameter(typeof(int), "val");
    var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    var lambda = Expression.Lambda<Func<int, Foo>>(
        Expression.New(ctor, param), param);
    var func = lambda.Compile();
    Foo foo = func(123);
    string s = foo.ToString(); // proof
Run Code Online (Sandbox Code Playgroud)

或(使用DynamicMethod):

    ConstructorInfo ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    DynamicMethod dm = new DynamicMethod("Create", typeof(Foo),
            new Type[] { typeof(int) }, typeof(Foo), true);
    ILGenerator il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, ctor);
    il.Emit(OpCodes.Ret);
    Converter<int, Foo> func = (Converter<int, Foo>)
        dm.CreateDelegate(typeof(Converter<int, Foo>));        
    Foo foo = func(123);
    string s = foo.ToString(); // proof
Run Code Online (Sandbox Code Playgroud)

  • 一旦编译为委托,基于反射的方法并不慢,并且(有时)比常规编译代码更快.显然你只编译一次并缓存委托. (6认同)
  • +1.这个(表达式实现)对我来说比接受的答案更有帮助,因为我需要cctor,而不是ctor. (4认同)
  • 呃哦;从技术上讲,使用反射等。是正确的(我也考虑了一下),但它有严重的缺陷:1)正如你的评论中所见,它严重损害了可读性(并使代码变得不那么简洁而不是更简洁);2)据我所知,反射比语言支持的构造慢,因为它多了一层抽象。 (2认同)

lep*_*pie 29

不,CLR不允许绑定代理ConstructorInfo.

但是,您可以创建自己的:

static T Make<T>(Action<T> init) where T : new()
{
  var t = new T();
  init(t);
  return t;
}
Run Code Online (Sandbox Code Playgroud)

用法

var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });
Run Code Online (Sandbox Code Playgroud)

  • 构造函数不会生成新对象.构造函数与分配例程一起使用. (7认同)
  • 另一种可能是狡猾的解决方案是通过一组`public static <SELF> Create <SELF>(/*args*/)`方法镜像所有ctors.因此你可以说`Func <string,string,Foo> = Foo.CreateFoo`. (2认同)

Ada*_*son 7

我认为你将得到的简洁(没有转向工厂模式)将是匿名方法,如下所示:

delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}
Run Code Online (Sandbox Code Playgroud)

这并没有严格按照你的要求进行(因为你将委托传递给一个返回新实例的匿名方法,而不是直接委托给构造函数),但我不认为你要求的是什么是严格可能的.

当然,这是假设您使用3.5+


Mon*_*ong 5

听起来你可能想要使用类工厂模式.

工厂方法模式