10
_callReportCode = reader["Call Report Code"].ToString();

I am attempting to handle the possibility for the object I am calling ToString on to be NULL. I am going to be using the above statement with several variables and I dont want to make an individual try/catch for each one... what is the best way to do null checking for strings.

Other datatypes ive been doing this:

int.TryParse(reader["Account Number"].ToString(), out _accountNumber);

In this code "reader" refers to a SqlDataReader but thats not really important for this question.

jth41
  • 3,808
  • 9
  • 59
  • 109
  • http://stackoverflow.com/a/10104842/195488 –  Apr 05 '13 at 13:39
  • Try/Catch would _not_ be the appropriate mechanism to use if you wanted to test individually - you should check if `reader['blah']` is `Null` before calling `.ToString()`. Exceptions should _never_ be part of your normal execution flow, they're expensive and not designed to be used in that way (eg too easy to catch the wrong thing if you don't think carefully) – Basic Apr 05 '13 at 13:44
  • 1
    Unrelated, but I'm curious as to what Account Number should be an integer. – Anthony Pegram Apr 05 '13 at 14:37
  • Even though I agree with the most voted answer, I believe you should write an extension method in order to reuse your code anywhere. I don't really like using repeating code over again. – Tarik Apr 11 '13 at 03:29

11 Answers11

32

Use the null-coalescing operator: ??

callReportCode = (reader["Call Report Code"] ?? "").ToString();

If the data in your field is DBNull.Value (rather than null), this will still work, because DBNull.Value is not null, so the ?? won't be used, and DBNull.Value.ToString() is "", which is what you'd want.

Bobson
  • 13,498
  • 5
  • 55
  • 80
  • It will throw NPE if the object is null –  Apr 05 '13 at 13:40
  • @0A0D - It'll only throw an exception if `reader` is null. This will work correctly if `reader["Call Report Code"]` is null. – Bobson Apr 05 '13 at 13:41
  • 1
    If the data is `DBNull`, you cannot use the null coalescing operator. – Matthew Apr 05 '13 at 13:43
  • 1
    @Matthew - Sure you can. `DBNull.Value.ToString()` returns `""`. – Bobson Apr 05 '13 at 13:47
  • 2
    `(DBNull.Value ?? "").ToString()` doesn't even compile – Andre Calil Apr 05 '13 at 13:49
  • 1
    if the reader returns null for that column name, it means the column itself doesn't exist, if it returns DBNull, it means the database returned a null value. They are two distinct things, one is an application problem (you're requesting a column that doesn't exist), and the other isn't (column values can be null [DBNull]). – Matthew Apr 05 '13 at 13:50
  • @AndreCalil - That doesn't compile, but `reader["Call Report Code"]` is of type `object`, so the actual scenario will. – Bobson Apr 05 '13 at 13:52
  • 1
    @Bobson Yes, but `DBNull` inherits from `Object` (http://msdn.microsoft.com/en-us/library/system.dbnull.aspx). I can see that you've never used it in a real project. It will return `DBNull` from the DB if the column is null, it's a very usual problem. – Andre Calil Apr 05 '13 at 13:54
  • 1
    You cannot convert `object` to `string` using the null coalescing, you could cast it to string, however if the underlying data is neither `null` (not `DBNull`) nor `string`, you will get a cast exception. If you try and cast `DBNull` to string, you will get a cast exception. – Matthew Apr 05 '13 at 13:54
  • @Matthew - `object foo = DateTime.Now; (foo ?? "").ToString();` works. `object foo = 2.3; (foo ?? "").ToString();` works. `object foo = null; (foo ?? "").ToString();` works. `object foo = DBnull.Value; (foo ?? "").ToString();` works. Give me an example where you get an exception with this pattern. – Bobson Apr 05 '13 at 13:57
  • Sorry, I was using an erroneous example of `string x = y ?? "";`, I was missing the `ToString` portion. – Matthew Apr 05 '13 at 14:06
  • @Matthew - It's ok, I've been there. I'm sorry I got so defensive about it. I use this pattern a lot, so I was pretty confident in it. – Bobson Apr 05 '13 at 14:08
  • 2
    No need to apologize, I was the one who made this mistake. – Matthew Apr 05 '13 at 14:10
11
Convert.ToString(reader["Call Report Code"]);

It will return string.Empty if the value is null.

Source: http://msdn.microsoft.com/en-us/library/astxcyeh.aspx

Update: it also works with DBNull, I've just verified.

Update 2: I decided to bring a more complete test here, just to be sure:

DBNull dbNull = null;
DBNull dbNullEmpty = DBNull.Value;
string stringNull = null;
string stringEmpty = string.Empty;

var outcome1 = Convert.ToString(dbNull);//Empty string
var outcome2 = Convert.ToString(dbNullEmpty);//Empty string
var outcome3 = Convert.ToString(stringNull);//NULL
var outcome4 = Convert.ToString(stringEmpty);//Empty string
Andre Calil
  • 7,652
  • 34
  • 41
  • It still throws an exception when I try this... _callReportCode = Convert.ToString(reader["Call Report Code"]); the whole point is to get it in that variable – jth41 Apr 05 '13 at 13:59
  • @John Can you share details of the exception? – Andre Calil Apr 05 '13 at 14:00
  • it does not seems to be working the way msdn says, can be checked by Convert.ToString(null).EndsWith(""); vs string.empty.EndsWith(""); The stmt Convert.ToString(null).EndsWith("") will throw object ref exception. – Anil Sep 30 '16 at 09:02
  • @AnilKumar yeah, but that's kinda expected. `Convert.ToString(null)` returns null, then you try to call the method `.EndsWith("")` from it. – Andre Calil Sep 30 '16 at 13:01
  • It will not return string.Empty if the value is null, it will return null. – Anil Oct 04 '16 at 10:06
  • @AnilKumar I've updated the answer to bring all the situations, please check it out. Thanks! – Andre Calil Oct 04 '16 at 15:29
3

If your string is nullable, you need to check the value returned from the SqlDataReader against DBNull.Value:

_callReportCode = reader["Call Report Code"] as string;

If the object returned by reader["Call Report Code"] is not a string, it's DBNull.Value, so the as cast is going to set the value of _callReportCode to null as well.

If you must set the string to a non-null in case the database value is missing, add ??, like this:

_callReportCode = (reader["Call Report Code"] as string) ?? string.Empty;
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

My suggestion is to never convert ToString when the data isn't a string, and if the data is already a string, then calling ToString is redundant, and a cast is all that's required.

I am making an assumption that the datatype in the database is integer, in which case, you can use a nullable int.

int? accountNumber = reader["Account Number"] == DBNull.Value ? null : (int?)reader["Account Number"];

I have made an extension method to do just this thing.

public static class SqlDataReaderExtensions
{
    public static T Field<T>(this SqlDataReader reader, string columnName)
    {
        object obj = reader[columnName];

        if (obj == null)
        {
            throw new IndexOutOfRangeException(
                string.Format(
                    "reader does not contain column: {0}",
                    columnName
                )
            );
        }

        if (obj is DBNull)
        {
            obj = null;
        }

        return (T)obj;
    }
}

Usage

int? accountType = reader.Field<int?>("Account Number"); // will return NULL or the account number.
Matthew
  • 24,703
  • 9
  • 76
  • 110
  • What do you do with the value later? like if I am going to pass it into a constructor? do I have to change that constructor to take a nullable int? – jth41 Apr 05 '13 at 13:44
  • That depends on your application, what does it mean to your application when `Account Number` is null? – Matthew Apr 05 '13 at 13:47
1

The easiest way I have found is

_callReportCode = reader["Call Report Code"] + "";
CADmageren
  • 45
  • 5
1

i have some easiest and common Method.

 public static string ToNULLString(this string Values)
        {
            if (string.IsNullOrEmpty(Values))
            {
                return "";
            }
            else
            {
                return Values.ToString();
            }
        }

use in C#

string item = null;
string value = item.ToNULLString();
Neo Vijay
  • 823
  • 9
  • 13
0

_callReportCode = Convert.ToString(reader["Call Report Code"]) should ensure there are no null there.

eXecute
  • 176
  • 7
0

you could create a method that you call when you want to make the check. This way you have to type the try catch only once... or you can create an extension method for string class to do this

Fabio Marcolini
  • 2,315
  • 2
  • 24
  • 30
0

Use following line of code:

_callReportCode = String.IsNullorEmpty(reader["Call Report Code"]) ?
                  String.Empty :
                  reader["Call Report Code"].ToString();

instead of the following line:

_callReportCode = reader["Call Report Code"].ToString();
Czar Pino
  • 6,258
  • 6
  • 35
  • 60
0

I like using a combination of the null-coalescing operator and the null conditional operator:

string nn = MyObject.myNullableVar?.ToString() ?? "";

it's basically the same as this

string ss = (MyObject.MyNullableVar == null) ? "" : MyObject.MyNullableVar.ToString();

but shorter.

RayLoveless
  • 19,880
  • 21
  • 76
  • 94
-1

You can perform a check using String.IsNullOrEmpty() to ensure that it isn't going to be null, or you could write an extension method to perform some action if it's not null and another / nothing if it is.

Clint
  • 6,133
  • 2
  • 27
  • 48