Reputation: 237
I'm using constructor injection for the first time and wish to write my code defensively.
Therefore if I have a class with a constructor and a save method as below:
public SomeConstructor(string name, Object someObject)
{
_name= name;
_someObject= someObject;
}
public void Save()
{
// Does a database save
}
But then need to create another related method in this Class that doesn't need the _someObject so I create an overloaded chained constructor as:
public SomeConstructor(string name) : this(name, null)
{
}
How can I successfully stop someone instantiating the class with this second constructor with 1 parameter and using the Save() which has someObject as null?
I'm not using an injection tool.
Above is a simple example and in it, you are correct I could just throw an exception for a null just as I would if a property was not set.
What I wanted to avoid was a series of validation checks at the start of each method.
Upvotes: 2
Views: 2368
Reputation: 61067
public void Save()
{
if (_someObject == null)
throw new InvalidOperationException();
}
I guess that this is obvious. But you really can't create a contract in which the type is constructed differently unless you also change your SomeConstructor
type to work like a decorator pattern. What the decorator pattern does is that it let's you build the inheritance hierarchy at run-time not compile-time.
You can then create different objects depending on what operations are allowed internally. This is some work for something which can easily be handled with a pre-condition for the Save
method. But maybe this is what you need. And if you did it you could stipulate your contract in the constructor of SomeConstructor
.
Here's an example:
interface ISomeConstructor
{
void Save();
}
class SomeConstructor
{
ISomeConstructor impl;
public SomeConstructor(string name, object someObject)
{
impl = new StringAndObject(name, someObject);
}
public SomeConstructor(string name)
{
impl = new JustString(name);
}
public void Save()
{
impl.Save();
}
}
The types StringAndObject
and JustString
implements ISomeConstructor
and they can handle the Save
method as they see fit.
This is a slight variation of the decorator pattern as normally you'd expect ISomeConstructor
to be passed as an argument to the constructor as well.
Upvotes: 0
Reputation: 233487
Use the friction you are experiencing as a warning system. It's really telling you that you're likely moving towards low cohesion and violation of the Single Responsibility Principle.
If this is the case, refactor the class into two separate classes.
Upvotes: 4
Reputation: 64943
You may prevent that situation with a run-time exception like InvalidOperationException.
If some instantiated the class with the two-parameters-constructor and tries to call Save, just check if "someObject" is null, and if it's so:
throw new InvalidOperationException("This method cannot be invoked in current object state");
In the other hand, if this second constructor would be used by your library and third-party library developers wouldn't be allowed to use it, this constructor should have the internal modifier.
Upvotes: 1
Reputation: 26737
The IoC it is just a way to dinamically resolve the dependency but doens't solve any OO problem. I would focus on a good OO design instead of try to find a way to cheat the framework forcing to use a contractor instead of another.The question is how would you do that if you were not using an IoC framework? probabily checking if SomeObject is null?
Upvotes: 0