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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1600712/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:15:09  来源:igfitidea点击:

a constructor as a delegate - is it possible in C#?

c#delegatesconstructor

提问by akavel

I have a class like below:

我有一个像下面这样的课程:

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

and I need to pass to a certain method a delegate like this:

我需要将这样的委托传递给某个方法:

delegate Foo FooGenerator(int x);

Is it possible to pass the constructor directly as a FooGeneratorvalue, without having to type:

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

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

?

?

EDIT:For my personal use, the question refers to .NET 2.0, but hints/responses for 3.0+ are welcome as well.

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

采纳答案by leppie

Nope, the CLR does not allow binding delegates to ConstructorInfo.

不,CLR 不允许将委托绑定到ConstructorInfo.

You can however just create your own:

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

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

Usage

用法

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

回答by Andrew Hare

Unfortunately not, constructors are not quite the same things as methods and as such you cannot create a delegate that points to them. This is an interesting idea though, perhaps with more information we could devise some sort of workaround that would be syntactically similar.

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

回答by Mongus Pong

It sounds like you probably want to be using the class factory pattern.

听起来您可能想要使用类工厂模式。

Factory Method Pattern

工厂方法模式

回答by Serge Wautier

My guess is that it isn't possible since you would pass a method of an object that has not been created yet.

我的猜测是这是不可能的,因为您将传递尚未创建的对象的方法。

回答by Adam Robinson

I think as concise as you're going to get (without moving to a factory pattern) would be something with anonymous methods, like this:

我认为尽可能简洁(不转向工厂模式)将是匿名方法,如下所示:

delegate Foo FooGenerator(int x);

...    

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

This isn't doing strictly what you asked for (since you're passing a delegate to an anonymous method that returns a new instance, rather than a direct delegate to the constructor), but I don't think what you're asking for is strictly possible.

这不是严格按照您的要求执行的(因为您将委托传递给返回新实例的匿名方法,而不是直接委托给构造函数),但我不认为您要求的是是绝对可能的。

This is, of course, assuming you're using 3.5+

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

回答by Marc Gravell

I'm assuming you would normally do something like this as part of a factory implementation, where the actual types aren't known at compile-time...

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

First, note that an easier approach may be a post-create init step, then you can use generics:

首先,请注意,更简单的方法可能是 post-create init 步骤,然后您可以使用泛型:

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

You can then use MakeGenericMethodand/or CreateDelegate.

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



Otherwise; you can do this with on the fly with Expression(3.5) or DynamicMethod(2.0).

除此以外; 您可以使用Expression(3.5) 或DynamicMethod(2.0)即时执行此操作。

The Expressionapproach is easier to code:

这种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

or (using DynamicMethod):

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

回答by Kim Homann

Marc Gravell's answer inspired me to the following very simple solution:

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

Almost the same thing if your constructor has params (in this example: 1 param of type int):

如果您的构造函数有参数,则几乎相同(在本例中: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 });
}

回答by Jim Fell

Another option would be to use the Activatorclass, like so:

另一种选择是使用Activator该类,如下所示:

Using Generic Types

使用泛型类型

public delegate Foo FooGeneratorDelegate<T>(int x);

public T FooGeneratorFunction<T>(int x)
{
    return (T)Activator.CreateInstance(typeof(T), x);
}

// implementation example
FooGeneratorDelegate<Foo> del = FooGeneratorFunction<Foo>;
Foo foo = del(someIntValue);

Passing Your Type Foo as a Parameter

将您的类型 Foo 作为参数传递

public delegate object FooGeneratorDelegate(Type t, int x);

public object FooGeneratorFunction(Type t, int x)
{
    return Activator.CreateInstance(t, x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = (Foo)del(typeof(Foo), someIntValue);

If the Type will Always be of Type Foo

如果类型始终是类型 Foo

public delegate Foo FooGeneratorDelegate(int x);

public Foo FooGeneratorFunction(int x)
{
    return (Foo)Activator.CreateInstance(typeof(Foo), x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = del(someIntValue);