【问题标题】:Factory that takes constructors接受构造函数的工厂
【发布时间】:2015-02-21 17:37:55
【问题描述】:

我怎样才能建立一个这样的工厂:

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");

我知道,我可以只使用类构造函数,但是这种模式可能有一些用途,我想知道这是否可能。

【问题讨论】:

  • 这不起作用,因为/*constructor parameters*/ 的数量(和类型)取决于T 是什么。 A 的实现者不受其构造函数可以采用的参数的限制。此外,一个类型可以公开 几个 构造函数。

标签: c# interface factory


【解决方案1】:

你可以做到,但它并不漂亮。

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&lt;T&gt;,它将按需生成实例:

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

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

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

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

【讨论】:

    【解决方案2】:

    这可以通过反射来实现:

    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"});
    

    【讨论】:

      【解决方案3】:

      你可以试试这样的 -

      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;
                  }
      

      【讨论】:

        猜你喜欢
        • 2012-01-31
        • 1970-01-01
        • 2014-07-13
        • 1970-01-01
        • 1970-01-01
        • 2015-06-04
        • 1970-01-01
        • 2021-06-10
        • 1970-01-01
        相关资源
        最近更新 更多