可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 FooGenerator value, without having to type:
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.
回答1:
Nope, the CLR does not allow binding delegates to ConstructorInfo.
You can however just create your own:
static T Make(Action init) where T : new() { var t = new T(); init(t); return t; }
Usage
var t = Make( x => { x.Bar = "bar"; x.Baz = 1; });
回答2:
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:
static T Create({args}) where T : class, ISomeInitInterface, new() { T t = new T(); t.Init(args); return t; }
You can then use MakeGenericMethod and/or CreateDelegate.
Otherwise; you can do this with on the fly with Expression (3.5) or DynamicMethod (2.0).
The Expression approach is easier to code:
var param = Expression.Parameter(typeof(int), "val"); var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) }); var lambda = Expression.Lambda>( Expression.New(ctor, param), param); var func = lambda.Compile(); Foo foo = func(123); string s = foo.ToString(); // proof
or (using 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 func = (Converter) dm.CreateDelegate(typeof(Converter)); Foo foo = func(123); string s = foo.ToString(); // proof
回答3:
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+
回答4:
It sounds like you probably want to be using the class factory pattern.
Factory Method Pattern
回答5:
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.
回答6:
Marc Gravell's answer inspired me to the following very simple solution:
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):
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 }); }
回答7:
My guess is that it isn't possible since you would pass a method of an object that has not been created yet.