MickJuice
MickJuice

Reputation: 539

Pass Function that is potentially a Null Reference Exception as a parameter

I'd like to write a helper method that takes a func and a second parameter T, and attempts to invoke it. If a Null Reference Exception occurs, return T (second parameter). If it's successful, return the result of the func passed in. So instead of:

tableRow[rowNum, fieldNamePos].Value != null ? tableRow[rowNum, fieldNamePos].Value.ToString() : "";

I could write

Helper.GetDefaultIfNull(tableRow[rowNum, fieldNamePos].Value.ToString,"")

Which I believe is more concise and less code. Here's what I have in the GetDefaultIfNull method:

public T GetDefaultIfNull<T>(Func<T> funcToInvoke, T defaultValue)
{
    T result;
    try
    {
       result = stringFunc.Invoke();
    }
    catch (NullReferenceException)
    {
       result = defaultValue;
    }

    return result;
}

When I run tests, this works correctly when passing in a non null reference, however when passing in a null reference, it throws an error when calling the method so it seems to be invoking the function while passing it into the method? Here is the test code:

[TestMethod]
    public void NULL_EXCEPTION_return_default()
    {
        StringBuilder sb = null;

        //Func<string> stringFunc = ; 
        var defaultValue = "";
        var result = new Helper().GetDefaultIfNull(sb.ToString, defaultValue);

        Assert.AreEqual(defaultValue, result);
    }

Is there a way to do this?

Upvotes: 1

Views: 1746

Answers (4)

Andrew Whitaker
Andrew Whitaker

Reputation: 126042

This is happening because by accessing a method this way on an object you're still dereferencing a null pointer. In other words, this line:

sb.ToString

is attempting to access a member (ToString) of a null reference (sb).

Changing the way you're calling your function would fix the problem:

var result = new Helper().GetDefaultIfNull(() => sb.ToString(), defaultValue);

That is, create a new Lambda and invoke that instead. The NullReferenceException you're expecting in your method will be thrown, caught, and handled the way you expect.

Upvotes: 3

Chaitanya
Chaitanya

Reputation: 1708

You can also have an alternative where you do a simple sanity check

public T GetDefaultIfNull<T>(Func<T> funcToInvoke, T defaultValue) {
    T result;
    if (funcToInvoke == null) {
        return result = defaultValue;
    }
    try {
        result = funcToInvoke.Invoke();
    } catch (Exception) {
        result = defaultValue;
    }

    return result;
}

And the test method is below.

//running a NUnit test
[Test]
public void NULL_EXCEPTION_return_default() {
    StringBuilder sb = null;
    var defaultValue = string.Empty;
    var result = new TestHelper().GetDefaultIfNull(sb.ToString, defaultValue);

    Assert.AreEqual(defaultValue, result);
}

Upvotes: 0

James
James

Reputation: 216

Give this a try:

public T GetDefaultIfNull<T>(Func<T> funcToInvoke, T defaultValue)
{
    T result;
    try
    {
        result = stringFunc.Invoke();
        if (result == null)
        {
             //Do something with result as it is not null
        }
        else{
            result = defaultValue;
        }
    }
    catch (Exception ex)
    {
        ex.Message;
    }

    return result;
}

Upvotes: 0

tvanfosson
tvanfosson

Reputation: 532455

The null reference is occurring when attempting to find the function, i.e, if sb is null then sb.ToString will throw a NullReferenceException. I would suggest that you might want to do something like

public T GetDefaultIfNull<T>(object value, T defaultValue)
{
     return value == null 
             ? defaultValue
             : Convert.ChangeType(value, typeof(T));
}

Then call it as

Helper.GetDefaultIfNull(tableRow[rowNum, fieldNamePos].Value, "");

Now, this assumes that the value is convertible to T but I'm assuming that you know what type it should be and the conversion operation would either be a no-op or you'd know that it will work.

Upvotes: 0

Related Questions