NullRefException on Cell.PutValue(obj) if obj.ToString() returns null

I have an object which overrides ToString() and returns null on certain conditions. If such an object is put into a cell, a NullReferenceException is thrown.

ExampleCode:

[TestMethod]
       public void Aspose_Test()
    {
        var wb = new Aspose.Cells.Workbook();
        wb.Worksheets[0].Cells["A1"].Value = new MyToStringClass(); //This line throws NullReferenceException
    }

    class MyToStringClass
    {
        public override string ToString()
        {
            return null; //ToString returning null causes issue while assigning the object to a cell
        }
    }

Can you have a look at it?

Workarround: Use the string-value itself to assign to the cell instead of using the object.

Version Used: Aspose.Cells for .NET - 21.4.0.0

For an user defined object, we can only take its string representation as cell’s value because for spreadsheet files a cell cannot hold user defined objects. And we cannot handle such special case with extra check for Cell.PutValue() either, it is because PutValue() is the most frequently used method for users, extra constraints may infect performance for most users. Please check your object by yourself before setting it as cell’s value. We think the simple and best way is that you get the ToString() result of your object and put the string to cell directly.

Thanks for your replay.
It is correct, that only the string representation of unknown objects can be used. However I think this exception should not be thrown.
A simple check if _param0 is null in the following method would increase the stability of your product (Sorry, I only have the mimified dissasembly)

internal static \u0002\u2007\u2008 \u0002(string _param0) { switch (_param0.Length) { case 0: return (\u0002\u2007\u2008) null; case 4: return _param0[0] == '#' && _param0[2] == '/' && ((int) _param0[1] | 32) == 110 && ((int) _param0[3] | 32) == 97 ? \u0002\u2007\u2008.\u0003 : (\u0002\u2007\u2008) null; case 5: if (_param0[0] != '#' || _param0[4] != '!') return (\u0002\u2007\u2008) null; return ((int) _param0[1] | 32) == 110 ? (((int) _param0[2] | 32) != 117 || ((int) _param0[3] | 32) != 109 ? (\u0002\u2007\u2008) null : \u0002\u2007\u2008.\u0006) : (((int) _param0[1] | 32) != 114 || ((int) _param0[2] | 32) != 101 || ((int) _param0[3] | 32) != 102 ? (\u0002\u2007\u2008) null : \u0002\u2007\u2008.\u000E); case 6: if (_param0[0] != '#') return (\u0002\u2007\u2008) null; return _param0[5] == '?' ? (((int) _param0[1] | 32) != 110 || ((int) _param0[2] | 32) != 97 || ((int) _param0[3] | 32) != 109 || ((int) _param0[4] | 32) != 101 ? (\u0002\u2007\u2008) null : \u0002\u2007\u2008.\u0005) : (_param0[5] != '!' || ((int) _param0[1] | 32) != 110 || ((int) _param0[2] | 32) != 117 || ((int) _param0[3] | 32) != 108 || ((int) _param0[4] | 32) != 108 ? (\u0002\u2007\u2008) null : \u0002\u2007\u2008.\u0008); case 7: if (_param0[0] != '#' || _param0[6] != '!') return (\u0002\u2007\u2008) null; return _param0[5] == '0' ? (_param0[4] == '/' && ((int) _param0[1] | 32) == 100 && ((int) _param0[2] | 32) == 105 && ((int) _param0[3] | 32) == 118 ? \u0002\u2007\u2008.\u0002 : (\u0002\u2007\u2008) null) : (((int) _param0[1] | 32) == 118 && ((int) _param0[2] | 32) == 97 && ((int) _param0[3] | 32) == 108 && ((int) _param0[4] | 32) == 117 && ((int) _param0[5] | 32) == 101 ? \u0002\u2007\u2008.\u000F : (\u0002\u2007\u2008) null); default: return (\u0002\u2007\u2008) null; } }

Please run my example and look at the place where the exception is thrown. It happens after .toString() is called on the unknown object. Then on the resulting string .length is called without checking if this string is null!

Thanks for reconsidering this issue

For parameters of single public method, it is reasonable to add such kind of check for the robustness of APIs and the performance influence can be ignored(for normal situations and most apis there is no too high frequency of invocations).

However, your input object is not null, so we cannot catch the abnormal input at the first step. For your situation, to find and prevent the abnormal value, we have to call ToString() for the object and check whether it is null. But calling ToString() for user’s input object is not always necessary for Cell.PutValue() method(in fact it is unnecessary at all for most users and cases of using this method) and it infects the performance much more than checking a null object.

As for the code you mentioned, as inner modules in our product, one method may have very high frequency of invocation(for example, in one formula calculation of one excel function there may be millions of calling or even much more). For such situations, we have to take performance into consideration and minimize those unnecessary checks as much as possible.

Thanks for your detailed response.
Your performance considerations do make a lot of sense and even if it is a small check, it still adds some CPU cycles to each PutCell(…).
I did solve this issue on my side by passing a proper string instead of the object, and wanted to inform you and other devs about this strange error message. I took me some time to find the root-cause of this NullRefException.
You can consider this issue as resolved.
Have a nice day.

Thank you for your feedback and understanding. If you get such kind of exception caused by our apis, you may provide us the required resources(code, template files, …etc) which can be used to reproduce the issue. With that we will be happy to help to figure the issue out.

1 Like