采用构造函数的工厂

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.CreateInstancenew 相比非常慢。您可以直接使用 Type.GetConstructor() 获取构造函数,这稍微快一些,但它 仍然很糟糕 .

像这样的解决方案往往过于聪明而不利于它们自己的利益。使用静态类型真的更好,即使是工厂。工厂的一种替代方案是接受 Func<T> 将按需生成实例:

void needToUseAnAForSomething(Func<A> aCreator) {
   ...
   A a = aCreator();
}

然后客户端代码可以做这样的事情:

needToUseAnAForSomething(() => new B("test"));

在这种情况下,当然我们可以直接传递实例,但在更复杂的场景中,这可以代替工厂构造。