采用构造函数的工厂
Factory that takes constructors
我怎样才能建立一个像这样的工厂:
interface A {
}
class B: A {
string b;
public B(string b) { this.b = b; }
}
class Factory {
public static T create<T>(/*somehow pass constructor parameters*/) where T: A {
return new T(/*constructor parameters*/);
}
}
B test = Factory.create<B>("test");
我知道,我可以只使用 class 构造函数,但这种模式可能有一些用途,我想知道这是否可行。
这可以通过反射来实现:
public static T Create<T> (object[] parameters) where T : class
{
Type[] parameterTypes = (parameters ?? Enumerable.Empty<object> ())
.Select (parameter => parameter.GetType ()).ToArray ();
ConstructorInfo ctor = type.GetConstructor (parameterTypes);
Debug.Assert (ctor != null);
T instance = ctor.Invoke (parameters) as T;
Debug.Assert (instance != null);
return instance;
}
您通过以下方式调用该方法:
B test = Factory.Create<B> (new object[]{"test"});
您可以尝试这样的操作 -
public static object create<T>(string param) where T : A
{
Type type = typeof(T);
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(string) });
object instance = ctor.Invoke(new object[] { param });
return instance;
}
你可以做到,但它并不漂亮。
class Factory {
public static T Create<T>(params object[] parameters) where T : A {
return (T) Activator.CreateInstance(typeof(T), parameters);
}
}
虽然这看起来很吸引人,但也存在问题:
- 您永远不会知道调用是否在运行时有效,在运行时它可能会抛出讨厌的异常。
- 参数的转换使得很难看出将调用哪个构造函数——如果有的话。
Activator.CreateInstance
与 new
相比非常慢。您可以直接使用 Type.GetConstructor()
获取构造函数,这稍微快一些,但它 仍然很糟糕 .
像这样的解决方案往往过于聪明而不利于它们自己的利益。使用静态类型真的更好,即使是工厂。工厂的一种替代方案是接受 Func<T>
将按需生成实例:
void needToUseAnAForSomething(Func<A> aCreator) {
...
A a = aCreator();
}
然后客户端代码可以做这样的事情:
needToUseAnAForSomething(() => new B("test"));
在这种情况下,当然我们可以直接传递实例,但在更复杂的场景中,这可以代替工厂构造。
我怎样才能建立一个像这样的工厂:
interface A {
}
class B: A {
string b;
public B(string b) { this.b = b; }
}
class Factory {
public static T create<T>(/*somehow pass constructor parameters*/) where T: A {
return new T(/*constructor parameters*/);
}
}
B test = Factory.create<B>("test");
我知道,我可以只使用 class 构造函数,但这种模式可能有一些用途,我想知道这是否可行。
这可以通过反射来实现:
public static T Create<T> (object[] parameters) where T : class
{
Type[] parameterTypes = (parameters ?? Enumerable.Empty<object> ())
.Select (parameter => parameter.GetType ()).ToArray ();
ConstructorInfo ctor = type.GetConstructor (parameterTypes);
Debug.Assert (ctor != null);
T instance = ctor.Invoke (parameters) as T;
Debug.Assert (instance != null);
return instance;
}
您通过以下方式调用该方法:
B test = Factory.Create<B> (new object[]{"test"});
您可以尝试这样的操作 -
public static object create<T>(string param) where T : A
{
Type type = typeof(T);
ConstructorInfo ctor = type.GetConstructor(new[] { typeof(string) });
object instance = ctor.Invoke(new object[] { param });
return instance;
}
你可以做到,但它并不漂亮。
class Factory {
public static T Create<T>(params object[] parameters) where T : A {
return (T) Activator.CreateInstance(typeof(T), parameters);
}
}
虽然这看起来很吸引人,但也存在问题:
- 您永远不会知道调用是否在运行时有效,在运行时它可能会抛出讨厌的异常。
- 参数的转换使得很难看出将调用哪个构造函数——如果有的话。
Activator.CreateInstance
与new
相比非常慢。您可以直接使用Type.GetConstructor()
获取构造函数,这稍微快一些,但它 仍然很糟糕 .
像这样的解决方案往往过于聪明而不利于它们自己的利益。使用静态类型真的更好,即使是工厂。工厂的一种替代方案是接受 Func<T>
将按需生成实例:
void needToUseAnAForSomething(Func<A> aCreator) {
...
A a = aCreator();
}
然后客户端代码可以做这样的事情:
needToUseAnAForSomething(() => new B("test"));
在这种情况下,当然我们可以直接传递实例,但在更复杂的场景中,这可以代替工厂构造。