How to set the value of string to null - c#

I am aware that I can set null like
string val = null;
But I am wondering the other ways I can set it to null. Is there a funcion like String.null that I can use.

I think you are looking far String.Empty
string val = String.Empty;
Update:
TheFuzzyGiggler comments are worth mentioning:
It's much better to set a string to empty rather than null. To avoid
exceptions later. If you have to read and write a lot of strings
you'll have null value exceptions all over the place. Or you'll have a
ton of if(!string.isNullorEmpty(string)) which get annoying

You can also use the default keyword.
string val = default(string);
Here is another SO question regarding the default keyword:
What is the use of `default` keyword in C#?

null is not a special string value (there's String.Empty for ""), but a general object literal for the empty reference.

Obviously one more way to set something to null is to assign result of function that returns null:
string SomeFunctionThatReturnsNullString() {return null;}
string val = SomeFunctionThatReturnsNullString();

assign it to this value will make it a null ,(chose the right sql datatype , here its double )
System.Data.SqlTypes.SqlDouble.Null

Depending on your application you could use string.Empty. I'm always leery of initializing to null as the garbage collector is great, but not perfect, and could mark your string for garbage collection if used in some way that the garbage collector can't detect (this is very unlikely though).

Related

Null safe string

I have a localzation string which apparently if set to null is causing issues in the view. So my solution was to string it.
_localizer["Controller_Account_ResetPassword_ResetFailed"].ToString();
During code review my co-worker reminded me that .ToString() is not null safe. While its highly unlikely that a localization would be null I guess it could be. He suggested the following.
TempData["Message"] = $"{_localizer["Controller_Account_ResetPassword_ResetFailed"]}";
I have two questions.
Why is $"{var}" null safe and .ToString() is not.
Is there a better way of doing it because his solution seams ugly to me.
First of all, the reason is that it's basically decompiled as
var arg = _localizer["Controller_Account_ResetPassword_ResetFailed"];
string.Format("{0}", arg);
and string.Format does a null check on its arguments and automatically replaces them with string.Empty.
Second of all, this solution is beautiful and string interpolation is an ingenious tool. You should use it :)
EDIT:
I kinda overlooked the fact here string interpolation is used solely to fix the null problem. As some have pointed out that is unnecessary and as much as everyone should love string interpolation something like this:
_localizer["Controller_Account_ResetPassword_ResetFailed"]?.ToString() ?? "";
would be a better choice.
I like to use a ToStringSafe extension method for these kind of scenarios
public static class Extensions
{
public static string ToStringSafe(this object value)
{
// return empty string
if (value == null) {
return String.Empty;
}
return value.ToString();
}
}
You can use the ?? operator to substitute "" if needed:
var something = _localizer["Controller_Account_ResetPassword_ResetFailed"] ?? "";
I wouldn't use $"{value}" notation here. First of all it probably is unneeded, second it does extra work by calling string.Format() which internally creates a StringBuilder object.
It also is by no means clear that the only and actual reason for calling $"{value}" would be to deal with a potential null value, which is 100% clear when you use ??.
As it was stated above the string interpolation is null-safe as it's converted internally to the string.Format. However to answer the second question the information of how you're going to handle rare case with null localization is required. The solution suggested by your colleague is good (I'd only recommend to extract the variable instead of inlining for better readability), but you possibly may want to fall back to the non-localized version of the message instead of getting empty string in case of localization absence or handle the situation in any other way. In that case you'll have to do the explicit null verification possibly inside the _localizer type implementation so that it's always guaranteed to return non-null values or fail.

"string s = null" is technically incorrect?

Please let me know if this is in the wrong place, or let me know a better place for it.
This question is not about the syntax, more the idea behind it.
I would like to know what null is essentially, or isn't as the case may be
First off, I just want to clarify exactly what null is. By my understanding, null is
technically nothing. So the statement
string s = null;
is technically incorrect? You are assigning a variable no value but a variable can't not have a value? Am I correct in thinking this?
My idea of null is that it's kind of like thinking, "If I go and get a drink of water, I will need a cup to put the water in". null is the space in which the data will be placed in, but the space doesn't exist yet. Following this idea:
string s = "";
would be more appropriate, no? And along this thought (though a bit less confusing)
int n = 0;
follows the same idea, where 0 is a value, but the value of 0 is nothing?
The original line of code is quite valid. In C#, any reference type variable can have no value, i.e. it refers to no object. null is quite different to an empty string. Consider a variable of some other type, e.g. Form. What would be the equivalent of an empty string then? A null in C# is basically the same as a NULL in a database.
Value types are a but different. Because reference type variables contain a reference, it is possible for them to refer to no object. Value type variables, on the other hand, contain a value and so cannot be null. A struct or enum is a value type and a class or delegate is a reference type. So, if a variable on the stack contains the value zero then, for a reference type that means no object, i.e. null, and for a value type that means the default value for that type, e.g. zero for numbers, false for bool and DateTime.MinValue for DateTime.
C# references are basically tarted-up pointers. Just as in C/C++ a pointer can be null to point to no object, so a C# reference-type variable can be null to refer to no object. In the case of strings, an empty string is an object and is very different to null. An empty balloon is still a balloon and very different to no balloon at all.
Your confusion likely lies in the difference between reference types and value types.
void Foo() {
string s = null;
}
This does not create a string. Instead, s is a reference to a string. However, s is currently referring to (or pointing to, in C terminology) nothing.
s ---> [nothing]
Now when we do this:
s = "Stack Overflow";
we are making s refer to that string. s itself doesn't contain the string.
s ----> "Stack Overflow"
Note that "" itself is a string, and does exist
s ----> ""
Strings are actually a bad example because of string interning.
Value types on the other hand line up with your confusion.
An int for example, must have a value. If you don't assign it one, it will (generally) take the default value of 0.
See more:
Value Types and Reference Types
This is not wrong as much as it is redundant because null is the default value of string
as int num = 0 is redundant because 0 is the default value of int
If you need to initialize your string then you should go for string s = "" or my personal favorite string s = string.Empty
Null means nothing. 0 is a value, but null means that there is no value. Actually in C#:
string s=null;
means that instance of the class string is null and has no value.
Imagine string s is just a variable pointing to a place in memory which was allocated for you.
string s = null; Is allocating a variable but it is not pointng to a place in your memory.
string s = "; micht be the same but it is pointing to a slot in your memory containing a iteral with an empty string.
I hope that made the problem a bit more clear.

String equality with null handling

I will often use this code to compare a string:
if(!string.IsNullOrEmpty(str1) && str1.Equals(str2)){
//they are equal, do my thing
}
This handles the null case first etc.
Is there a cleaner way to do string comparison, perhaps with a single method call that will handle possible null values? I simply want to know that the strings are not equal if the testing value is null.
(I'm having dejavu that I may have asked this before, I apologize if so)
Update: In my case, the str2 is a known good string to compare to, so I don't need to check it for null. str1 is the "unknown" string which may be null, so I want to say "str1 does not equal str2" in the cases where str1 is null...
Unlike Java, C# strings override the == operator:
if (str1 == str2)
If you want a case-insensitive comparison:
if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase))
If you do not want to treat two null strings as equal to each other, your code is optimal.
If, on the other hand, you want to treat null values as equal to each other, you can use
object.Equals(str1, str2)
for a more "symmetric" approach that also handles null values.
This is not the only approach to a symmetric check of string equality that treats null strings as equal: you could also use string.Equals(str1, str2) or even str1 == str2, which redirects to string.Equals.
I know this is some years old and I think the solution from dasblinkenlight is functionally perfect for what you asked for.
However I do prefer this code for readability reasons:
String.Equals(str1, str2)
There is no built in way to do this, but you could create an extension method to encapsulate this.
public static StringExtensions
{
public static Boolean IsNotNullAndEquals(this string str1, string str2)
{
return !string.IsNullOrEmpty(str1) && str1.Equals(str2)
}
}
then use it like this:
str1.IsNotNullAndEquals(str2);
Naming is going to be your hardest thing here IMO...since you need to convey that you are only null checking str1. When used as an extension method, it reads fairly well, but if used as a regular static, then it doesn't convey that as well.
You can use this code
object.Equals(str1, str2)
This will do it:
string.IsNullOrWhiteSpace(str1) ? string.IsNullOrWhiteSpace(str2) : str1.Equals(str2, StringComparison.OrdinalIgnoreCase);
I know this has been answer while ago and there's good answers, although as per Microsoft documentation (https://learn.microsoft.com/en-us/dotnet/api/system.string.equals?view=net-5.0) you can use the following to check both cases:
if(string.Equals(str1,str2)){
//they are equal with null handling
}
In more recent C# versions, we also have the null coalescing option now. This isn't an exact solution but can be a cleaner one for some purposes. It takes some liberties with "upgrading" str1 to an empty string for comparison purposes, in the instances where it actually is a null.
if((str1??"").Equals(str2))
{
//they are equal, do things here
}

What is the difference in string.Equals("string") and "String".Equals(string)?

Is there any difference in following two lines of code that compares the string values.
string str = "abc";
if(str.Equals("abc"))
and
if("abc".Equals(str))
in the first line I am calling the equals method on string variable to compare it with string literal. The second line is vice versa. Is it just the difference of coding style or there is a difference in the way these two statements are processed by the compiler.
The only difference is that, in the first case, when you do:
str.Equals("abc")
If str is null, you'll get an exception at runtime. By doing:
"abc".Equals(str)
If str is null, you'll get false.
The difference is that in the second example, you will never get a NullReferenceException because a literal can't be null.
To add to the other answers: the static string.Equals("abc", str) method always avoids triggering a null reference exception, regardless of which order you pass the two strings.
As mmyers said, you the second example will not throw a NullReferenceException and while allowing the program to "appear" to run error free, may lead to unintended results.
Yes, the way the compiler processed the statements is different. The function equals for String in most languages follows the same guidlines. Here is a semicode:
override def Equals(that:String):Boolean //Should override Object.Equals
if(that==null) return false
for i from 0 to this.length
if(!this(i).Equals(that(i))) return false
return true
Normally, the method will fisrt check that that IS a String, and that this and that have the same length.
You can see, as others pointed out, that if that is null the method returns false. On the other hand, the method is part of of String so it cannot be called on null. That is why in your exampleif str is null you will get a NullReferenceException.
That being said, if you know both variables are non-null Strings of the same length, both statements will evaluate to the same in the same time.

What is the best way to deal with DBNull's

I frequently have problems dealing with DataRows returned from SqlDataAdapters. When I try to fill in an object using code like this:
DataRow row = ds.Tables[0].Rows[0];
string value = (string)row;
What is the best way to deal with DBNull's in this type of situation.
Nullable types are good, but only for types that are not nullable to begin with.
To make a type "nullable" append a question mark to the type, for example:
int? value = 5;
I would also recommend using the "as" keyword instead of casting. You can only use the "as" keyword on nullable types, so make sure you're casting things that are already nullable (like strings) or you use nullable types as mentioned above. The reasoning for this is
If a type is nullable, the "as" keyword returns null if a value is DBNull.
It's ever-so-slightly faster than casting though only in certain cases. This on its own is never a good enough reason to use as, but coupled with the reason above it's useful.
I'd recommend doing something like this
DataRow row = ds.Tables[0].Rows[0];
string value = row as string;
In the case above, if row comes back as DBNull, then value will become null instead of throwing an exception. Be aware that if your DB query changes the columns/types being returned, using as will cause your code to silently fail and make values simple null instead of throwing the appropriate exception when incorrect data is returned so it is recommended that you have tests in place to validate your queries in other ways to ensure data integrity as your codebase evolves.
If you aren't using nullable types, the best thing to do is check to see if the column's value is DBNull. If it is DBNull, then set your reference to what you use for null/empty for the corresponding datatype.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
As Manu said, you can create a convert class with an overloaded convert method per type so you don't have to pepper your code with if/else blocks.
I will however stress that nullable types is the better route to go if you can use them. The reasoning is that with non-nullable types, you are going to have to resort to "magic numbers" to represent null. For example, if you are mapping a column to an int variable, how are you going to represent DBNull? Often you can't use 0 because 0 has a valid meaning in most programs. Often I see people map DBNull to int.MinValue, but that could potentially be problematic too. My best advice is this:
For columns that can be null in the database, use nullable types.
For columns that cannot be null in the database, use regular types.
Nullable types were made to solve this problem. That being said, if you are on an older version of the framework or work for someone who doesn't grok nullable types, the code example will do the trick.
Add a reference to System.Data.DataSetExtensions, that adds Linq support for querying data tables.
This would be something like:
string value = (
from row in ds.Tables[0].Rows
select row.Field<string>(0) ).FirstOrDefault();
I always found it clear, concise, and problem free using a version of the If/Else check, only with the ternary operator. Keeps everything on one row, including assigning a default value if the column is null.
So, assuming a nullable Int32 column named "MyCol", where we want to return -99 if the column is null, but return the integer value if the column is not null:
return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]);
It is the same method as the If/Else winner above - But I've found if you're reading multiple columns in from a datareader, it's a real bonus having all the column-read lines one under another, lined up, as it's easier to spot errors:
Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]);
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]);
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]);
If you have control of the query that is returning the results, you can use ISNULL() to return non-null values like this:
SELECT
ISNULL(name,'') AS name
,ISNULL(age, 0) AS age
FROM
names
If your situation can tolerate these magic values to substitute for NULL, taking this approach can fix the issue through your entire app without cluttering your code.
DBNull implements .ToString() like everything else. No need to do anything. Instead of the hard cast, call the object's .ToString() method.
DataRow row = ds.Tables[0].Rows[0];
string value;
if (row["fooColumn"] == DBNull.Value)
{
value = string.Empty;
}
else
{
value = Convert.ToString(row["fooColumn"]);
}
this becomes:
DataRow row = ds.Tables[0].Rows[0];
string value = row.ToString()
DBNull.ToString() returns string.Empty
I would imagine this is the best practice you're looking for
It is worth mentioning, that DBNull.Value.ToString() equals String.Empty
You can use this to your advantage:
DataRow row = ds.Tables[0].Rows[0];
string value = row["name"].ToString();
However, that only works for Strings, for everything else I would use the linq way or a extension method. For myself, I have written a little extension method that checks for DBNull and even does the casting via Convert.ChangeType(...)
int value = row.GetValueOrDefault<int>("count");
int value = row.GetValueOrDefault<int>("count", 15);
Often when working with DataTables you have to deal with this cases, where the row field can be either null or DBNull, normally I deal with that like this:
string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;
The 'as' operator returns null for invalid cast's, like DBNull to string, and the '??' returns
the term to the right of the expression if the first is null.
You can also test with Convert.IsDBNull (MSDN).
I usually write my own ConvertDBNull class that wraps the built-in Convert class. If the value is DBNull it will return null if its a reference type or the default value if its a value type.
Example:
- ConvertDBNull.ToInt64(object obj) returns Convert.ToInt64(obj) unless obj is DBNull in which case it will return 0.
For some reason I've had problems with doing a check against DBNull.Value, so I've done things slightly different and leveraged a property within the DataRow object:
if (row.IsNull["fooColumn"])
{
value = string.Empty();
}
{
else
{
value = row["fooColumn"].ToString;
}
Brad Abrams posted something related just a couple of days ago
http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx
In Summary "AVOID using System.DBNull. Prefer Nullable instead."
And here is my two cents (of untested code :) )
// Or if (row["fooColumn"] == DBNull.Value)
if (row.IsNull["fooColumn"])
{
// use a null for strings and a Nullable for value types
// if it is a value type and null is invalid throw a
// InvalidOperationException here with some descriptive text.
// or dont check for null at all and let the cast exception below bubble
value = null;
}
else
{
// do a direct cast here. dont use "as", "convert", "parse" or "tostring"
// as all of these will swallow the case where is the incorect type.
// (Unless it is a string in the DB and really do want to convert it)
value = (string)row["fooColumn"];
}
And one question... Any reason you are not using an ORM?
You should also look at the extension methods. Here are some examples to deal with this scenerio.
Recommended read
If you are concerned with getting DBNull when expecting strings, one option is to convert all the DBNull values in the DataTable into empty string.
It is quite simple to do it but it would add some overhead especially if you are dealing with large DataTables. Check this link that shows how to do it if you are interested

Categories

Resources