一个构造函数作为代表 – 它可能在C#中?
我有一个类如下:
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
。
但是,您可以创build自己的:
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; });
我假设你通常会做这样的工厂实现的一部分,实际types不知道在编译时…
首先,请注意,更简单的方法可能是创build后的init步骤,那么您可以使用generics:
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+
这听起来像你可能想要使用类工厂模式。
工厂方法模式
不幸的是,构造函数与方法不太一样,所以你不能创build一个指向它们的委托。 尽pipe这是一个有趣的想法,也许有了更多的信息,我们可以devise一些类似于句法的解决方法。
马克·格雷维尔(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); }
几乎相同的事情,如果你的构造函数有参数(在这个例子中:1参数typesint):
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 }); }
我的猜测是,这是不可能的,因为你会传递一个尚未创build的对象的方法。