handling nulls in c# - c#

I have an object like this:
class MyObject
{
public string Object.Prop1 { get; set; }
public string Object.Prop2 { get; set; }
}
I'm writing a custom JSON converter and I'm serializing this object like this:
Dictionary<string, object> OutputJson = new Dictionary<string, object>();
OutputJson.Add("TheProp1", MyObject.Prop1.Trim());
If for some reason Prop1 is null, will the code encode TheProp1 as "" or will it crash?

If Prop1 is null your code will throw a NullReferenceException. You need to test if Prop1 is null before calling Trim:
MyObject.Prop1 == null ? "" : MyObject.Prop1.Trim()
Or you can do it more concisely with the null-coalescing operator:
(MyObject.Prop1 ?? "").Trim()

Another way to handle this is to use private member to handle the property values of properties where you need a default value rather than null
Class MyObject
{
private string _prop1 = String.Empty;
public string Object.Prop1 {
get
{
return _prop1;
}
set
{
_prop1 = value;
}
}
}

It will crash with a NullReferenceException, since you can't call Trim on null. You could do this instead:
OutputJson.Add("TheProp1", MyObject.Prop1 == null ?
string.Empty :
MyObject.Prop1.Trim());

My understanding is that a null is not an empty string. If you want to insure that this is going to work simply wrap the Value of the add in an if and insert your empty string as the null place holder. Of course you'll need to take the appropriate action when you decode your json.

If you don't need polymorphic behaviour for MyObject you can declare it as a struct instead of a class. It will have value semantic and every value will be initialize using its default. I am assuming inside your class you have just struct type (eg. int, string, double).

you can use DBNull class in filling the object
UserName = DBNull.Value != reader["UserName"] ? reader["UserName"].ToString() : default(string);

Related

Selecting first non null value in a model

Let's say I have a model class that looks like this:
public class ModelTest {
public string val1 {get;set;}
public string val2 {get;set;}
public string val3 {get;set;}
}
Somewhere in my code this ModelTest gets its data. The caveat is that, only 1 of them will hold a value
var model = new ModelTest() {val1=null, val2="value", val3=null} //Sudo code
What I am trying to do somehow, is compare a value to whichever 1 of the 3 items can potentially have a values, so something like:
var testCompare = "someValue"
if (testCompare == model. ....//how can I get the NOT NULL value from ModelTest here for comparison
While your data model isn't ideal, it is possible to check each of the properties by utilizing the || operator to compare each value. As long as your testCompare variable does not contain null, you can also omit a null check.
if (model.val1 == testCompare ||
model.val2 == testCompare ||
model.val3 == testCompare)
{ }
As mentioned in the comments, if you want a more succinct version, you can use the null coalescing operator, ??, to check subsequent properties if your prior property returns null. At the end of the null coalescing chain, the first non-null property will be compared to your testCompare string. Note that you must wrap all three properties in parentheses and that this has different behavior; it only tests the first non-null property whereas the previous version tests ALL properties for a match.
if (testCompare == (model.val1 ?? model.val2 ?? model.val3))
{
}
You could add a property to your ModelTest class that provides the first non-null value (if any) in your object:
public class ModelTest
{
public string val1 { get; set; }
public string val2 { get; set; }
public string val3 { get; set; }
public string val => val1 ?? val2 ?? val3;
}
and then check against that:
if (model.val == testCompare) { }
You could probably create a method (or even property) like:
public string Val()
{
if (val1 != null) return val1;
if (val2 != null) return val2;
if (val3 != null) return val3;
return null;
}
There is probably a shorter way to write this code. Also, if two or more of the values are not null, then it will return the first one.
It's a very bizarre use case, but let's go with it. Here's another option for the bonfire..
public class ModelTest {
private string _val;
public string val1 {get => _val; set => _val ??= value;}
public string val2 {get => _val; set => _val ??= value;}
public string val3 {get => _val; set => _val ??= value;}
}
Whichever one of these is set to non null ends up committing that value to _val - ??= writes the right hand into the left hand only if the left hand is null, essentially like left = left ?? right.
It doesn't matter which you use to access the value..
Note that there is only one data storage location so this approach is incapable of remembering two values, or which value was the non null. You wouldn't use this for disparate properties like name, address and social security number because it could lead to bizarre effects elsewhere. This is for a very narrow use case of "there are three properties that are essentially the same thing, they cannot be collapsed to one, and I don't know which one will be set but i can treat them equivalent for reading"
You can override the method 'Equals' of ModelTest class however you like. Example:
public class ModelTest {
public string val1 {get;set;}
public string val2 {get;set;}
public string val3 {get;set;}
public override bool Equals(object obj)
{
if(!typeof(string).IsInstanceOfType(obj))
return base.Equals(obj);
string value = obj as string;
if (val1.Equals(value))
return true;
if (val2.Equals(value))
return true;
if (val3.Equals(value))
return true;
return false;
}
}
For to use the method:
if(model.Equals("yourValue"))
...
What about solution which contains combination of reflection and Linq,
Test Data
var model = new ModelTest() {val1=null, val2="value", val3=null} ;
Usage
var result =
model.GetType()
.GetProperties()
.FirstOrDefault(prop => prop.GetValue(model, null) != null);
Print result
Console.WriteLine(result.GetValue(model));
This is my first attempt with reflection, suggestions are most welcome
.Net fiddle
Note: This is just an alternate solution, less performant. If you are looking for elegant solution, then kindly try other solutions.

How to convert a nullable datetime value to string.empty when datetime is null?

I'm reading back a nullable DateTime? property then assigning that value to a string property in short date format.
I can convert the date time value to a short date string and assign to the IT_Date_String property. But I'm not sure how to assign a "" value to the string if the IT_Date is null.
How can you convert a datetime? value to string.empty when datetime? is null?
This is the assignment in linq:
var status_list = query_all.ToList().Select(r => new RelStatus
{
IT_Date_String = r.IT_Date.Value.ToString("yyyy-MM-dd") != null ? r.IT_Date.Value : null
}).ToList();
And the properties in the model:
public DateTime? IT_Date { get; set; }
public string IT_Date_String { get; set; }
You're calling the IT_Date.Value.ToString(...) regardless of whether IT_Date actually has a value.
So you need to turn the expression around:
r.IT_Date.HasValue ? r.IT_Date.Value.ToString(...) : ""
This way ToString() will only be called when IT_Date has a value.
You can also implement this in the getter, as mentioned in a now-deleted comment:
public string IT_Date_String
{
get
{
return IT_Date.HasValue ? IT_Date.Value.ToString(...) : "";
}
}
This way you won't have to reimplement the logic everywhere you access this model, and as a bonus, it will only be executed when it's actually requested.
There's also no need to explicitly use String.Empty, the string "" will be interned to the same at runtime.
In C# 6 you can do this:
IT_Date_String = r.IT_Date?.ToString("yyyy-MM-dd") ?? String.Empty;
The new ? checks if the thing on the left is null, if it is, the expression evaluates to null. If not, it just continues the evaluation.
Then, ?? checks whether the result of the first expression is null, which it would be if IT_Date is null. If it is, evaluate to String.Empty.
With C# 6.0 and null propagation you can use:
IT_Date_String = r.IT_Date?.ToString("yyyy-MM-dd") ?? String.Empty
This one will work in any version of the framework:
IT_Date_String=string.Format("{0:yyyy-MM-dd}",IT_Date);

Why am I getting a null reference error when accessing a string property?

Update: Thank you all very much for the information. I was struggling with it until I started typing out an update here. Had to talk it out. I had code that was pulling from the DB:
potentials[k].Address1 = reader.IsDBNull(reader.GetOrdinal("Address1"))
? string.Empty // that was reading null...
: reader.GetString(reader.GetOrdinal("Address"));
Original post:
public class PotentialInformation
{
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
}
public class PotentialCollection : IEnumerable
{
private Dictionary<string, PotentialInformation> listOfPotentials = new Dictionary<string, PotentialInformation>();
public PotentialInformation this[string k]
{
get { return listOfPotentials[k]; }
set { listOfPotentials[k] = value; }
}
public void Filter()
{
foreach (KeyValuePair<string, PotentialInformation> a in listOfPotentials)
{
Console.WriteLine("Addr1 {0} {1}, addr2 {2} {3}, addr3 {4} {5}",
a.Value.Address1.ToString(),
a.Value.Address1.GetType(),
a.Value.Address2.ToString(),
a.Value.Address2.GetType(),
a.Value.Address3.ToString(),
a.Value.Address3.GetType()
);
}
The error thrown:
System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
In each of the rows cases, there is an entry in Address1, but Addresses2 and 3 are null or empty.
I've tried doing:
if( String.IsNullOrEmpty(a.Value.Address2) == false )
if( String.IsNullOrEmpty(a.Value.Address2.ToString()) == false )
Something about the way I'm handling the nulls in Address2 and 3 is wrong, but I'm new to C# and having a hard time figuring out what it is. Thanks.
In C# there is a difference between an empty string and a null object reference. A null object is an unassigned reference whereas an empty string is an assigned object reference to a string object which has an empty value (i.e. one is not an object, one is an object but with no value).
Use your constructor to assign string.Empty value and your null reference exception will go away as you can call methods on an empty string object but not on a null reference.
string is a reference type and like any reference type if not initialized you will get a NullReferenceException if you try to access it try to create a private field something like this
private string _adress1 = string.Empty ;
and then you can do something like this
public string Address1
{ get {return _adress1;} set{ _adress1=value;} }
NullReferenceException occurs anytime you call a member or method on a null object, since the CLR can't handle trying to find member which literally don't exist. This means that Address2.GetType() or Address3.ToString() will throw the exception if the Address2 or Address3 are null.
The best way to fix this is to check whether Address2/Address3 are null before calling any of their member functions - in your second example, the exception is thrown because your second if statement doesn't check Address3, and the second line is still calling .ToString() against Address2.
You can also fix this by assigning an empty string to Address2 and Address3 in the constructor of PotentialInformation - since string is a class, the default value is null rather than and empty string.

How are you supposed to write attributes with null values in XML

Im using linq to xml to write out a little config file for an application and was a little surprised to discover XAttributes dont accept null as their value - they throw an exception instead.
Null is a perfectly valid value for many of the properties in my config and I dont want to have to null check attributes everywhere:
var attribute = _element.Attribute(attribute);
var value = attribute == null ? null : attribute.Value;
A further reason I dont want to write code like this is that it will make it easier to mis type names of things - eg if an attribute is spelled wrong it will just act like an attribute that exists but has a null value rather than throwing an exception.
The solution I have at the moment is as follows but it seems a little bit ugly + like something you shouldnt need to do.
I've knocked up a little class to make it a bit easier to write + read xml and am using a string containing just the null character to signal a null string.
I've omitted everything except the indexer for brevity:
public class XContainerWrapper
{
private readonly XElement _element;
public XContainerWrapper(XElement xElement)
{
_element = xElement;
}
public string this[string attribute]
{
get
{
var value = _element.Attribute(attribute).Value;
return value == "\0" ? null : value;
}
set
{
var valueToWrite = value ?? "\0";
_element.Add(new XAttribute(attribute, valueToWrite));
}
}
}
You can write your own extension method instead of XAttribute Value getter:
public static class XmlExtensions {
public static string SafeValue(this XAttribute attribute) {
var value = attribute == null ? null : attribute.Value;
return value;
}
}
Then you can use
XAttribute a = null;
var value = a.SafeValue();

Is there a null handler to string method at c#

I am able to assign a variable like below:
if (Session["myVariable"] != null)
{
string variAble = Session["myVariable"].ToString();
}
Is there a method which checks whether an object is null or not and then assign if it is not null?
string variAble = Session["myVariable"] ?? "";
EDIT A slightly more robust form, as suggested by #hatchet, is:
string variAble = (Session["myVariable"] ?? "").ToString();
While this isn't anything new, you can use the conditional operator to potentially simplify this:
string variable = Session["myVariable"] != null ? Session["myVariable"].ToString() : "Fallback";
You could write an extension method, as those still work with null objects.
public static class StringExtensions
{
public static String ToNullString(this object o)
{
return o == null ? "" : o.ToString();
}
}
I would consider it poor form though - it'll be confusing to whoever will be supporting the code after you, or even to you a few months down the track. It's probably better to just do the null check.

Categories

Resources