So I have this property and would like to either set the value to what is coming back from the db or to null if it is empty. It is possible to do this with an if-else, but for cleaner code, I would like to use the ternary operator. Could someone point out the mistake I am making. Thanks!!!
public DateTime? OptionExpiration {get;set;}
//actually sets the value to null
if(String.IsNullOrEmpty(dr["OPTION_EXPIRATION"].ToString())){
OptionExpiration = null;
}else{
OptionExpiration = DateTime.Parse(dr["OPTION_EXPIRATION"].ToString());
}
//so I check the to see if the string is empty or null, then try to set the value but recieve this error: Error 2 Operator '|' cannot be applied to operands of type '' and 'System.DateTime?'
String.IsNullOrEmpty(dr["OPTION_EXPIRATION"].ToString())
? OptionExpiration = null
| OptionExpiration = DateTime.Parse(dr["OPTION_EXPIRATION"].ToString())
;
You are using the ternary operator wrong.
It should be:
OptionExpiration = String.IsNullOrEmpty(Convert.ToString(dr["OPTION_EXPIRATION"]))
? (DateTime?)null
: DateTime.Parse(dr["OPTION_EXPIRATION"].ToString())
;
So:
assignment = condition ? trueExpression : falseExpression;
If the field is a date in your database, it might be better to do this:
OptionExpiration = Convert.IsDBNull(dr["OPTION_EXPIRATION"])
? (DateTime?)null
: (DateTime)dr["OPTION_EXPIRATION"]
;
I would use an extension method like this:
public static Nullable<DateTime> AsNullableDateTime(this object item, Nullable<DateTime> defaultDateTime = null)
{
if (item == null || string.IsNullOrEmpty(item.ToString()))
return defaultDateTime;
DateTime result;
if (!DateTime.TryParse(item.ToString(), out result))
return defaultDateTime;
return result;
}
You can pass anything in to this and it will attempt to give you back a date. If it fails for whatever reason (this also checks to make sure the object you send through is not null) you will get a null back; which is fine because you're mapping to a nullable datetime.
To use this you would do something like:
OptionExpiration = dr["OPTION_EXPIRATION"].AsNullableDateTime();
No mess, easy to understand what is happening, abstracting away the clutter, and highly reusable on other parts of your solution.
Related
I'm trying to get values from my database, it works when all columns have values. When a value is NULL, it returns an error.
I've managed to find a way to handle with the strings but if there's an integer I don't know how to handle it. I've tried to find a solution but none has worked for me so far! Here's the code, any help would be highly appreciated.
Thanks!
while (dr.Read())
{
coments comentsar = new coments
{
Id = (int)dr["Id"],
Name = (string)dr["Name"],
Likes = (int)dr["Likes"],
// Signature = dr["Signature"].ToString(),
Datetime = (DateTime)dr["Datetime"]
};
comen.Add(comentsar);
return comen;
}
You can check for null value and if the value is not null assign the variable using ternary operator:
Signature = dr["Signature"] != DBNull.Value ? (string)dr["Signature"] : "No value",
Likes = dr["Likes"] != DBNull.Value ? Convert.ToInt32(dr["Likes"]) : 0,
You need to change your types to Nullable types.
Change (int)dr["Likes"] to (int?)dr["Likes"]
and Datetime = (DateTime)dr["Datetime"] to Datetime = (DateTime?)dr["Datetime"].
You will also need to update your model coments to allow for nullable types.
Microsoft Nullable Types.
_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.
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.
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
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;
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.
The easiest way I have found is
_callReportCode = reader["Call Report Code"] + "";
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();
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
_callReportCode = Convert.ToString(reader["Call Report Code"]) should ensure there are no null there.
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();
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.
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.
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.
I am returning a scalar value from a SQL Server 2008 database:
string reason = cmd.ExecuteScalar().ToString() ?? : "";
I want to make sure that if null is returned, that reason = "" and not null.
i am getting an error on this line:
Error 3 Invalid expression term ':'
How can this be fixed?
EDIT:
thank you for the changes on the colon, now i am getting this exception on the same line:
string reason = cmd.ExecuteScalar().ToString() ?? "";
System.NullReferenceException occurred
Message="Object reference not set to an instance of an object."
Try this:
string reason = cmd.ExecuteScalar().ToString() ?? "";
BUT: this will still fail, since if .ExecuteScalar() returns a NULL, you're already causing a Null Reference Exception by calling .ToString() on that NULL value......
So I guess the ?? operator really doesn't help you here... do the "usual" dance:
object result = cmd.ExecuteScalar();
if(result != null)
{
reason = result.ToString();
}
else
{
reason = "(NULL value returned)";
}
First, you shouldn't have the : when using the ?? operator.
Second, to do what you are trying to do here without getting an error, you need to do it differently:
object objReason = cmd.ExecuteScalar();
string reason = objReason == null ? "" : objReason.ToString();
This will check whether or not your returned value is null and if it is, the second line will set reason to a blank string, otherwise it will use your returned value.
Since ExecuteScalar() returns object that might be null you should not call .ToString() since that may throw and exception.
string reason = Convert.ToString(cmd.ExecuteScalar());
This works because Convert.ToString() will convert null to string.Empty
or if you must use ?? because you really like it:
(cmd.ExecuteScalar() ?? (object)"").ToString();
Just get rid of the colon.
string reason = cmd.ExecuteScalar().ToString() ?? "";
For reference, check the MSDN page.
When using the null-coalescing operator, you don't need the colon:
string reason = cmd.ExecuteScalar().ToString() ?? "";
As others have pointed out though, ToString() would cause a NullReferenceExcpetion to be thrown anyway...so you don't gain anything here. You'd be much better off splitting this into multiple lines:
var result = cmd.ExecuteScalar();
string reason = result == null ? "" : result.ToString();
You're confusing the ? conditional operator, the syntax for which looks like this:
String x = condition ? valueIfConditionIsTrue : valueIfConditionIsFalse;
with the ?? null-coalesce operator whose syntax is as follows:
String x = possiblyNull ?? valueIfPossiblyNullIsNull;
So, apart from all that... this is the part you really want:
String reason = (cmd.ExecuteScalar() ?? "").ToString();
This takes care of your exception where ToString() was causing a null-reference exception.
Just use
string reason = cmd.ExecuteScalar() ?? "";