简体   繁体   中英

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:

public MyBaseClass(MySpecParam param){...}

But there is no guarantee that type T , derived from MyBaseClass , has such a constructor.

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.

But, MyBaseClass has such design, so it's completely unusable if it is not inited with MySpecParam . And user can create MyBaseClass with parameterless constructor and get completely invalid, not initialized, object. I think it's not good.

There is no way to add new(MySpecParam) constraint.

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 .

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. 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.

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

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

Alternatively, consider the abstract factory pattern .

Sounds like a problem for an IoC container. If your factory used a container like StructureMap or Unity, your constructor issue would no longer be a concern. 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.

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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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