作为委托的构造函数 - 它可能在C#中吗?
-
05-07-2019 - |
题
我有一个如下课程:
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 });
}
我的猜测是,由于您要传递尚未创建的对象的方法,因此无法实现。
不隶属于 StackOverflow