So I have created a provider (a few of them actually) and I am realising there is a bit of a pattern in some of my logic. It is being repeated and I reckon I can remove lots of lines of code if I can just create this extension method :D
So, basically what is happening is something like this:
// Get our item to be deleted
var model = await this._service.GetAsync(id);
// If we have nothing, throw an error
if (model == null)
throw new HttpException(404, string.Format(Resources.GenericNotFound, "List item"));
Now, I do this in a lot of places, not just for deleting, but for updating. I would like to create an extension method that allows me to do something like this:
// Get our item to be deleted
var model = await this._service.GetAsync(id).ThowIfNull("List item");
I also need this to work with any return type. So in this case it might be an Account, but there will be a provider that also has this code returning an Order but I need the extension method to work for both.
I think the challenge here is the async bit, but I might be wrong!
Anyone know if it is possible?
Very well you can call a static method with null object.
Yes. The compiler optimizes the code to invoke the static method using null object reference since object instance is not required to invoke a static method.
You can call a static method on a null pointer. The pointer will naturally be completely ignored in a static method call, but it's still a case when something that (without looking at the class definition) seemingly should cause a NullPointerException runs just fine.
A static method can also provide an array as a return value.
One possibility to avoid the async-await part is to make the extension method work on the type returned inside of the Task
public static T ThrowIfNull<T>(this T obj, string message) where T : class
{
if (obj == null)
throw new HttpException(404, string.Format(Resources.GenericNotFound, message));
return obj;
}
I made the extension method generic as I don't know what type model
is. Then you can just use it like this.
var model = (await this._service.GetAsync(id)).ThrowIfNull("List item");
By putting the await
in parenthesis you make sure it will wait on the task and unwrap it before passing the result to the extension method.
The other option would be to make the extention method work on Task<T>
public static async Task<T> ThrowIfNullAsync<T>(this Task<T> task, string message)
where T : class
{
var obj = await task;
if (obj == null)
throw new HttpException(404, string.Format(Resources.GenericNotFound, message));
return obj;
}
And you wouldn't need the parenthesis.
var model = await this._service.GetAsync(id).ThrowIfNullAsync("List item");
But this means that the exception is now wrapped in the task which may or may not be desirable depending on how you use this method.
You can define an extension method on any T
:
public static class GenericExtensions
{
public static T ThrowIfNull<T>(this T obj, string message)
{
if (obj == null)
throw new HttpException(404,
string.Format(Resources.GenericNotFound, message));
return obj;
}
}
If you don't care about the return type you can use object
, but that will incur boxing for value types (not sure I'd use this actually):
public static class ObjectExtensions
{
public static void ThrowIfNull(this object obj, string message)
{
if (obj == null) throw new ArgumentNullException(message);
}
}
And then use it on any return type:
async Task SomeAsyncMethod()
{
(await Foo()).ThrowIfNull("hello");
}
public Task<int> Foo()
{
return Task.FromResult(0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With