Reputation: 12805
Consider a factory method that I may or may not control, passed to another class as a Func<T>
:
// this.FactoryMethod is an external dependency passed into this class
// through constructor or property injection assume that it is not null
// but there is no guarantee that it will return a non-null reference.
Func<IModel> FactoryMethod;
public IModel GetPopulatedModel(int state, FileInfo someFile)
{
// Argument validation omitted for brevity...
// This operation could return null.
var model = this.FactoryMethod()
if (model == null)
{
throw new SomeException("Factory method failed to produce a value.");
}
// Safe to assign to properties at this point.
model.Priority = state;
model.File = someFile;
return model;
}
I would like to throw something that indicates the operation failed.
ArgumentNullException
would be misleading because there is nothing wrong with the arguments:
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method that does not accept it as a valid argument.
InvalidOperationException
doesn't really seem to be on point:
The exception that is thrown when a method call is invalid for the object's current state.
It seems weird to consider a local variable to be part of the object's current state
.
What would be good exception to throw? I'm surprised there is no OperationFailedException
in System
. Should I write my own exception, or is there a good one out there?
Upvotes: 2
Views: 6304
Reputation: 21002
NotImplementedException is definitely not the correct choice here. Its intended meaning is "not implemented yet", and it should pretty much never be thrown by production code.
The most important criterion for what to throw in this scenario is what would be most useful to the consumer(s) of the exception. If you expect that calling code might need to react differently to this exception than to any arbitrary exception, the exception type is very important. On the other hand, the only thing that calling code would ever do with such an exception is to log it, its message is very important, and its type is somewhat less important. In the latter case, an InvalidOperationException with an explicit message would probably be quite suitable.
It's also worth thinking about whether the return of the null value from the factory method should be considered a violation of its contract or not. The fact that you want to throw an exception in this case suggests that it probably should be, in which case you might want to change the design a bit so that an interface instance is injected instead of a Func<>
. This would allow you to define either a documented contract on the interface method, specifying that it will never return null, and that it will throw an exception if it can't create a model instance. If you're using Code Contracts, you could even make the non-null return value part of its explicit contract.
On a last little note, if you think that NullReferenceException is an acceptable thing to throw here (which your response to another answer would seem to indicate), you can accomplish this by simply letting the model.Priority = state
line execute. The only problem with this (which is shared by any other approach in which GetPopulatedModel throws an exception after receiving a null model instance from the factory) is that the source location of the exception isn't particularly helpful to a developer who is trying to figure out why the retrieved model was null. This is why "encouraging" the factory to throw its own exception might be the best candidate approach.
Upvotes: 2
Reputation: 12805
Another option: don't throw an exception. In the actual application, the method is called from within a try/catch block, and this exception would have been caught and logged. There was no advantage to throwing an exception in this case.
So instead of throwing the exception, I just logged the message and returned null. Translating this to the example code looks like this:
// this.FactoryMethod is an external dependency passed into this class
// through constructor or property injection assume that it is not null
// but there is no guarantee that it will return a non-null reference.
Func<IModel> FactoryMethod;
public IModel GetPopulatedModel(int state, FileInfo someFile)
{
// Argument validation omitted for brevity...
// This operation could return null.
var model = this.FactoryMethod()
if (model == null)
{
this.Logger.Write("Factory method failed to produce a value.");
return null;
}
// Safe to assign to properties at this point.
model.Priority = state;
model.File = someFile;
return model;
}
If throwing an exception were required/useful, I would have gone with NotImplementedException
, but in this case, not throwing an exception made more sense.
Upvotes: 0
Reputation: 217361
Two examples from the .NET Framework:
The SecurityTokenParameters.Clone Method throws an InvalidOperationException if the SecurityTokenParameters.CloneCore Method returns null.
InvalidOperationException Class
The exception that is thrown when a method call is invalid for the object's current state.
The ClientCredentials.Clone Method throws a NotImplementedException if the ClientCredentials.CloneCore Method returns null.
NotImplementedException Class
The exception that is thrown when a requested method or operation is not implemented.
CloneCore is essentially a factory method for clones of the current object.
I would use a NotImplementedException, because the factory method does not implement what is requested from it.
Upvotes: 3
Reputation: 31
Why not use the InvalidOperationException() since you don't have the control on the Method used if it fail it means that it was invalid.
Upvotes: 1
Reputation: 67115
You can always create your own Exception if you feel that the available exceptions at your disposal are not adequate.
UPDATE
Although, I do agree with @TomTom and @dtb as to the possible options that are out there. Especially the NotImplementedException
as the factory is indeed not implemented
Upvotes: 5
Reputation: 26909
I'm not sure this is really the Factory pattern you're implementing here. But to answer your question, just make a custom exception as follows:
public class FactoryNullException : Exception
{
public FactoryNullException() : base("Factory was null")
{
}
}
Upvotes: 0
Reputation: 62137
InvalidOperationException.
A local variable is what defines the object's state per definition. Nothing bad. The factory method must be set, or you can not create objects. InvalidOperation - factory can not create object at that moment because the factories internal state is wrong for that.
Upvotes: 2
Reputation: 8718
I would create my own exception called something like
FactoryNullException
Then you can even create the default message you want, e.g., the one in your example
Factory method failed to produce a value.
Upvotes: 2