简体   繁体   English

工厂方法的构造函数上的类型约束

[英]Type constraints on constructor for factory method

I found that my design is wrong and asking you how solve my problem. 我发现我的设计是错误的,并询问您如何解决我的问题。

So my case: 所以我的情况:

I'm writing factory method, for classes, witch was derived from my special base class. 我正在编写工厂方法,对于类,女巫是从我的特殊基类派生的。 So I wrote 所以我写了

public T MyFactory<T>() where T:MyBaseClass

But my the main work of my factory method is getting some special parameters and passing it to constructor of new object. 但是,我工厂方法的主要工作是获取一些特殊参数并将其传递给新对象的构造函数。 MyBaseClass has this constructor: MyBaseClass具有以下构造函数:

public MyBaseClass(MySpecParam param){...}

But there is no guarantee that type T , derived from MyBaseClass , has such a constructor. 但是,不能保证从MyBaseClass派生的T类型具有此类构造函数。

The only solution I see, is to add new() constraint and virtual Init method to MyBaseClass , so that the factory can safely create a new object of type T , and then init it with MySpecParam object. 我看到的唯一解决方案是向MyBaseClass添加new()约束和虚拟Init方法,以便工厂可以安全地创建类型为T的新对象,然后使用MySpecParam对象对其进行MySpecParam

But, MyBaseClass has such design, so it's completely unusable if it is not inited with MySpecParam . 但是, MyBaseClass具有这样的设计,因此,如果不使用MySpecParam它,将完全无法使用。 And user can create MyBaseClass with parameterless constructor and get completely invalid, not initialized, object. 用户可以使用MyBaseClass参数构造函数创建MyBaseClass并获得完全无效(未初始化)的对象。 I think it's not good. 我觉得不好

There is no way to add new(MySpecParam) constraint. 无法添加new(MySpecParam)约束。

How must I design my objects, constructors and factory method? 我该如何设计对象,构造函数和工厂方法?

If each class has only one public constructor, you can find that by reflection, determine what parameters it takes, and supply the appropriate values when you call the constructor (still through reflection). 如果每个类只有一个公共构造函数,则可以通过反射找到它,确定它需要使用哪些参数,并在调用构造函数时提供适当的值(仍然通过反射)。

Otherwise, I presume you have a finite set of constructor signatures. 否则,我假设您有一组有限的构造函数签名。 In that case, you'll need some way of determining which constructor to call; 在这种情况下,您将需要某种方法来确定要调用的构造函数。 the decision may be based in part on the identity of the type argument T . 该决定可以部分地基于类型自变量T的身份。

EDIT 编辑

If you're not willing to use reflection for the reasons outlined in your comment, then the answer is more or less "no, you can't do that." 如果您出于评论中概述的原因不愿意使用反射,那么答案或多或少是“不,您不能那样做”。 Michael Yoon suggests an IoC framework, which of course uses reflection and is subject to run-time errors as well. Michael Yoon建议使用一个IoC框架,该框架当然使用反射,并且也会遇到运行时错误。 In my experience (with Castle Windsor), performance has never been a problem, and run-time errors as the result of misconfiguration are caught almost immediately in the development cycle. 根据我的经验(使用Castle Windsor),性能从来都不是问题,并且由于配置错误而导致的运行时错误几乎在开发周期中立即被发现。

Another thought; 另一个想法; this may not be helpful, but it might be worth considering. 这可能没有帮助,但可能值得考虑。 You could use a Func<T> to create the instance, or even have overloads of the factory method for different types of Func<T, TOut> , Func<T1, T2, TOut> , etc, where you call 您可以使用Func<T>创建实例,甚至可以对不同类型的Func<T, TOut>Func<T1, T2, TOut>等类型的工厂方法进行重载,在其中调用

var obj = FactoryMethod<SomeType>(() => new SomeType(23));

Alternatively, consider the abstract factory pattern . 或者,考虑抽象工厂模式

Sounds like a problem for an IoC container. 听起来像是IoC容器的问题。 If your factory used a container like StructureMap or Unity, your constructor issue would no longer be a concern. 如果您的工厂使用了诸如StructureMap或Unity之类的容器,则不再需要担心构造函数问题。 The factory would ask StructureMap (for example) to resolve MyBaseClass, and it would return an instance your MyBaseClass using the greediest constructor, recursively building all of its dependencies and so forth. 工厂将要求StructureMap(例如)解析MyBaseClass,然后将使用贪婪的构造函数返回MyBaseClass的实例,并递归地构建其所有依赖项,依此类推。

Constructors are not inherited, nor are they allowed on interfaces. 构造函数不能继承,也不能在接口上使用。 This means that each class's constructor are specific only to that class. 这意味着每个类的构造函数仅特定于该类。 That also means that a subclass could be made of your base class that doesn't have a constructor that matches your pattern. 这也意味着子类可以由不具有与您的模式匹配的构造函数的基类组成。 If you want to have a standard way of configuring your objects, I think an abstract Init(foo, bar, baz) , on your base class, similar to your idea, is the best solution. 如果您想以一种标准的方式配置对象,我认为与您的想法类似,在您的基类上使用abstract Init(foo, bar, baz)是最好的解决方案。 You could also implement internal logic that throws if the objects are accessed before they are initialized, but unfortunately, you won't be able to enforce that at compile time. 您也可以实现内部逻辑,如果在初始化对象之前访问了对象,则抛出该逻辑,但是不幸的是,您将无法在编译时强制执行该逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM