我有一个如下课程:

class Foo
{
  public Foo(int x) { ... }
}

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

delegate Foo FooGenerator(int x);

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

delegate(int x) { return new Foo(x); }

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

有帮助吗?

解决方案

不,CLR不允许将代理绑定到 ConstructorInfo

然而,您可以创建自己的:

static T Make<T>(Action<T> init) where T : new()
{
  var t = new T();
  init(t);
  return t;
}

用法

var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });

其他提示

我假设您通常会在工厂实现中执行此类操作,其中实际类型在编译时是未知的...

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

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

然后您可以使用 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

或(使用 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

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

delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}

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

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

听起来你可能想要使用班级工厂模式。

工厂方法模式

不幸的是,构造函数与方法并不完全相同,因此您无法创建指向它们的委托。这是一个有趣的想法,也许有了更多的信息,我们可以设计一些在语法上相似的解决方法。

Marc Gravell的回答激发了我以下非常简单的解决方案:

static void Main()
{
    Pet a = _MakeObject(typeof(Dog));
    Pet b = _MakeObject(typeof(Cat));
}

private static Pet _MakeObject(Type type)
{
    ConstructorInfo info = type.GetConstructor(new Type[0]);
    return (Pet)info?.Invoke(null);
}

如果你的构造函数有params(在这个例子中:1个int类型的参数)几乎相同的事情:

static void Main()
{
    Pet a = _MakeObject(typeof(Dog), 5);
    Pet b = _MakeObject(typeof(Cat), 7);
}

private static Pet _MakeObject(Type type, int age)
{
    ConstructorInfo info = type.GetConstructor(new [] { typeof(int) });
    return (Pet)info?.Invoke(new object[] { age });
}

我的猜测是,由于您要传递尚未创建的对象的方法,因此无法实现。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top