We have a file called "StringExtensions" which works as a "class" which can be used for multiple datasets/models I assume.
Can anyone help understand what this ToSafeString does to a string?
public static string ToSafeString(this object source)
{
return source?.ToString() ?? string.Empty;
}
It checks if the object is not null with source?. If it is not null, then ToString() is called and the result is returned. If it is null, thenstring.Empty returned.
It uses (.?) null conditional and (??) null-coalescing operators.
Firstly source?. checks to see if the object being passed in is null, if it is that entire portion (source?.ToString()) will return null and due to the ?. operator the .ToString() does not get evaluated. This operator is short hand and is equivalent to writing:
if(source != null) {
return source.ToString();
} else {
return null;
}
Next, the null coalescing operator ( ?? ) kicks in and it will return string.Empty instead of just a null if either source or the return from .ToString() was null.
If called with null it will return string.Empty
If called on an object that has a .ToString() method that returns null, it will also return string.Empty
If called with an object that has a value to return from .ToString() it will return that value.
Related
I have a scenario where I am assigning value to a class property in the below way.
var appResponse = GetAppResponse();
appResponse.LogoImage = GetAppImage(appId);
The problem here is sometimes GetImage(appId) returns null and in that case I don’t want to assign that null value to appResponse.LogoImage, only when GetImage(appId) returns a value then only I want to assign that value.
I can use an If condition to check if GetImage(appId) is returning null or not and then assign the value, but then I will be making 2 calls to the method GetImage() which is not a good approach I feel.
In a single line can I check for null and when it is not null then only assign value to appResponse.LogoImage?
I can use a If condition to check if GetImage(appId) is returning null
or not and then assign the value, but then I will be making 2 calls to
the method GetImage()
Why would you be calling it twice?
Here's just one call:
var appResponse = GetAppResponse();
var appImage = GetAppImage(appId);
if (appImage != null) {
appResponse.LogoImage = appImage;
}
You could use the null-coalescing operator: ??
appResponse.LogoImage = GetAppImage(appId) ?? appResponse.LogoImage;
From the docs:
The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null; otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.
In order to validate if model comes null or not I use something like this:
if (model is null || !model.Any()) return this;
But in latest Microsoft conference I saw guys use something like:
if(model is { })
I try to use it but always return true (if object comes null or not)
So my question is. Is there a new way to check if a model comes null?
What is the correct usage of brackets { }
Note: I googled about that brackets but I found anything. Regards
You can do a generic extension method to check if your object is null or not.
Try:
public static bool IsNullOrEmpty<T>(this IEnumerable<T> source) {
return source?.Any() != true;
}
Another way to check for NullOrEmpty is to coerce Count() to an int?. Then we can compare the result of GetValueOrDefault to 0:
if((model?.Count).GetValueOrDefault() == 0) return this;
How it works:
Because the ?. operator will return null if the left side is null, and Count returns an int, the result of (model?.Count) is a Nullable<int>.
The GetValueOrDefault method returns the value of Count if model is not null, otherwise it returns default(int) (which is 0).
This way if model is null, the condition returns 0
I have read several articles and questions on Stack Overflow and still cannot see what I am doing wrong. Not using C#6 -- sorry for not posting that at first. VS 2013.
This code works:
if (row.Cells["CSR_Notes"].Value != null)
{
deliveryEvent.CSR_Notes = row.Cells["CSR_Notes"].Value.ToString();
}
and this code works:
deliveryEvent.CSR_Notes = row.Cells["CSR_Notes"].Value != null
? row.Cells["CSR_Notes"].Value.ToString() : "";
But this code throws a "Object reference not set..." error if the value is null.
deliveryEvent.CSR_Notes = row.Cells["CSR_Notes"].Value.ToString() ?? "";
What am I missing?
The issue is that Value is the potentially null property. By calling the ToString() method on it, you are creating the Null Reference Exception before the null coalescing operator has a chance to be used. You can fix this with the Null Propagating Operation from C# 6, like so:
deliveryEvent.CSR_Notes = row.Cells["CSR_Notes"].Value?.ToString() ?? "";
Notice the ? after Value. This is the Null Propagating operator. It will pass null through the rest of the expression if Value is null, which will then trigger the Null Coalescing Operator (??) properly.
The C# 5 solution would be to push the coalescing up a bit, as in haim770's answer.
deliveryEvent.CSR_Notes = (rows.Cells["CSR_Notes"].Value ?? "").ToString();
You need to check that the row.Cells["CSR_Notes"] object is not null, but your last code snippet is checking the returned value of the entire expression row.Cells["CSR_Notes"].Value.ToString() and by the time it's evaluated it rightly throws because row.Cells["CSR_Notes"] returns null.
Try this instead:
deliveryEvent.CSR_Notes = (row.Cells["CSR_Notes"].Value ?? "").ToString();
See MSDN
You are calling .ToString() on an object that is null. That's why you receive the error. Here's a simpler reproduction:
MyObject obj = null;
string result = obj.ToString();
You can avoid this by using the null conditional operator (sometimes known as "elvis operator")
deliveryEvent.CSR_Notes = row.Cells["CSR_Notes"].Value?.ToString() ?? "";
This will only call .ToString() on Value if Value is not null.
I'm attempting to dump variable property information to a simple string but when it gets to my nullable bools, the as string always returns null --even if the actual value is true | false!
StringBuilder propertyDump = new StringBuilder();
foreach(PropertyInfo property in typeof(MyClass).GetProperties())
{
propertyDump.Append(property.Name)
.Append(":")
.Append(property.GetValue(myClassInstance, null) as string);
}
return propertyDump.ToString();
No exceptions are thrown; quick and the output is exactly what I want except any properties that are bool? are always false. If I quick watch and do .ToString() it works! But I can't guarantee other properties are not, in fact, null.
Can anyone explain why this is? and even better, a workaround?
A bool is not a string, so the as operator returns null when you pass it a boxed boolean.
In your case, you could use something like:
object value = property.GetValue(myClassInstance, null);
propertyDump.Append(property.Name)
.Append(":")
.Append(value == null ? "null" : value.ToString());
If you want to have null values just not append any text, you can just use Append(Object) directly:
propertyDump.Append(property.Name)
.Append(":")
.Append(property.GetValue(myClassInstance, null));
This will work, but leave null properties in your "propertyDump" output as missing entries.
The as operator returns a casted value if the instance is of that exact type, or null otherwise.
Instead, you just should .Append(property.GetValue(...)); Append() will automatically handle nulls and conversions.
The nicest solution would be, in my opinion:
.Append(property.GetValue(myClassInstance, null) ?? "null");
If the value is null, it will append "null", and if not - it will call the value's ToString and append that.
Combining that with Linq instead of a foreach loop, you can have a nice little something:
var propertyDump =
string.Join(Environment.NewLine,
typeof(myClass).GetProperties().Select(
pi => string.Format("{0}: {1}",
pi.Name,
pi.GetValue(myClassInstance, null) ?? "null")));
(Looks nicer in the wide screen of VS).
If you compare speeds, by the way, it turns out the string.Join is faster than Appending to a StringBuilder, so I thought you might want to see this solution.
That's because the type of the property is not string. Change it to:
Convert.ToString(property.GetValue(myClassInstance, null))
If it's null, it will retrieve null and that's ok. For non-null values it will return the string representation of the value of the property.
You cannot cast a bool to a string. You must use ToString()
Use the null coalesing operator to handle the Null situations:
void Main()
{
TestIt tbTrue = new TestIt() { BValue = true }; // Comment out assignment to see null
var result =
tbTrue.GetType()
.GetProperties()
.FirstOrDefault( prp => prp.Name == "BValue" )
.GetValue( tb, null ) ?? false.ToString();
Console.WriteLine ( result ); // True
}
public class TestIt
{
public bool? BValue { get; set; }
}
I have a class with a string property. I use the coalesce operator when reading from it as it might be null, but it still throws me an NullRefrenceExeption.
string name = user.Section.ParentSection.Name ?? string.Empty;
To be more specific, its the ".ParentSection" that's null so is it because it don't even have ".name" ? If that's the case should i test ".ParentSection" first with an if block?
I assume there are something about the Coalesce operator i dont understand, hope someone can shed some light on whats going wrong here.
To be more specific, its the ".ParentSection" that's null so is it
because it don't even have ".name" ?
Yes.
If that's the case should i test ".ParentSection" first with an if
block?
Yes.
You'll need to check if Section and ParentSection are null. You could use an if-statement for this or write an extension method like this:
public static class MaybeMonad
{
public static TOut With<TIn, TOut>(this TIn input, Func<TIn, TOut> evaluator)
where TIn : class
where TOut : class
{
if (input == null)
{
return null;
}
else
{
return evaluator(input);
}
}
}
You would use this method like so:
string name = user.With(u => u.Section)
.With(s => s.ParentSection)
.With(p => p.Name) ?? string.Empty;
I think it's a lot cleaner than an if-statement with a lot of &&.
Some further reading: http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad
You need to check if user, user.Section, or user.Section.ParentSection are null before you can use the null coalescing operator on a property of user.Section.ParentSection.
Nested property access is not safe if any of the objects accessed are null this will throw a NullReferenceException. You will have to explicitly test for the outer objects to be not null.
E.g.:
string name = string.Empty;
if(user!=null && user.Section!=null && user.Section.ParentSection !=null)
name = user.Section.ParentSection.Name ?? string.Empty;
In general I would try to avoid nested access to properties, you are violating the Law of Demeter. Some refactoring might make this unnecessary in the first place.
The ?? operator checks if the left side is null and if so returns the right one, if not the left one.
In your case the left-side is the "Name" property in the object user.Section.ParentSection and this is null.
In those cases either think on what might be null or do something like this:
string name = user == null
|| user.Section == null
|| user.ParentSection == null
|| user.Section.ParentSection.Name == null
? string.Empty
: user.Section.ParentSection.Name;
(yeah it's ugly I know)
Chances are user or user.Section or user.Section.ParentSection is a null value.
The ?? operator doesn't prevent checks like:
if (user != null && user.Section != null && user.Section.ParentSection != null){
Make sure that everything up to the string property is valid and exists, then you can use ??. You can't call (null).Name, no matter how many times you try.
Yes you need to check if Section or ParentSection are null before you check Name
It is probably best to do something like this:
if(user!=null && user.Section!=null && user.Section.ParentSection!=null)
{
string name = user.Section.ParentSection.Name ?? string.Empty;
}
The null coalescing operator takes a statement like:
a = b ?? c;
What this says is "evaluate b; if it has a non-null value then assign that to a. Otherwise assign the value of c to a".
However within your b you're using a user object which may be null that has a section object that may be null that has a parent section property that may be null that had a name property that may be null. If you wanted to check all of these (and typically you should) then you can do something like:
string name = string.Empty;
if (user != null &&
user.Section != null &&
user.Section.ParentSection != null)
{
name = user.Section.ParentSection.Name ?? string.Empty;
}
As soon as the IF check fails it will not check further and therefore you don't get a NullReferenceException when you assume an object is present and then try to access one of its properties.