Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static Method for handling null returns

Tags:

c#

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?

like image 500
r3plica Avatar asked Sep 01 '16 14:09

r3plica


People also ask

Can we call static method on null object?

Very well you can call a static method with null object.

Can we pass null in static method in Java?

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.

Can you call a method on a null object?

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.

Can static methods have return values?

A static method can also provide an array as a return value.


2 Answers

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.

like image 50
juharr Avatar answered Oct 10 '22 06:10

juharr


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);
}
like image 3
Yuval Itzchakov Avatar answered Oct 10 '22 05:10

Yuval Itzchakov