Why can't I assign null to decimal with ternary operator? - c#

I can't understand why this won't work
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text)
? decimal.Parse(txtLineCompRetAmt.Text.Replace(",",""))
: null;

Because null is of type object (effectively untyped) and you need to assign it to a typed object.
This should work:
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text)
? decimal.Parse(txtLineCompRetAmt.Text.Replace(",",""))
: (decimal?)null;
or this is a bit better:
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text)
? decimal.Parse(txtLineCompRetAmt.Text.Replace(",",""))
: default(decimal?);
Here is the MSDN link for the default keyword.

Don't use decimal.Parse.
Convert.ToDecimal will return 0 if it is given a null string. decimal.Parse will throw an ArgumentNullException if the string you want to parse is null.

Try this:
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text) ?
decimal.Parse(txtLineCompRetAmt.Text.Replace(",", "")) :
(decimal?) null;
The problem is that the compiler does not know what type nullhas. So you can just cast it to decimal?

decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text) ?
decimal.Parse(txtLineCompRetAmt.Text.Replace(",","")) :
(decimal?)null;

Because the compiler can't infer the best type from the operands of the conditional operator.
When you write condition ? a : b, there must be an implicit conversion from the type of a to the type of b, or from the type of b to the type of a. The compiler will then infer the type of the whole expression as the target type of this conversion. The fact that you assign it to a variable of type decimal? is never considered by the compiler. In your case, the types of a and b are decimal and some unknown reference or nullable type. The compiler can't guess what you mean, so you need to help it:
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text)
? decimal.Parse(txtLineCompRetAmt.Text.Replace(",",""))
: default(decimal?);

You need to cast the first part to decimal?
decimal? compRetAmount = !string.IsNullOrEmpty(txtLineCompRetAmt.Text)
? (decimal?)decimal.Parse(txtLineCompRetAmt.Text.Replace(",",""))
: null;

Related

Set default value to null when converting to double in c#

I want to pass the null if the string is empty while converting from string to double. Can somebody help me with the syntax? As where I going wrong?
Current Syntax:
IngredientMinRange = !string.IsNullOrEmpty(MinRange) ? Convert.ToDouble(MinRange) : null
A double cannot be null since it's a value- and not a reference type. You could use a Nullable<double> instead:
double? ingredientMinRange = null;
if(!string.IsNullOrEmpty(MinRange))
ingredientMinRange = Convert.ToDouble(MinRange);
If you later want the double value you can use the HasValue and Value properties:
if(ingredientMinRange.HasValue)
{
double value = ingredientMinRange.Value;
}
Using Nullable Types (C# Programming Guide)
If IngredientMinRange is already a Double?-property as commented you can assign the value either via if(as shown above) or in in one line, but then you have to cast the null:
IngredientMinRange = string.IsNullOrEmpty(MinRange) ? (double?)null : Convert.ToDouble(MinRange);
to assign null to a double you have to use Nullable<double> or double?. Assign it with this method here:
decimal temp;
decimal? IngredientMinRange = decimal.TryParse(MinRange, out temp) ? temp : (decimal?)null;
then you can continue working with IngredientMinRange. You get the value with IngredientMinRange.Value or check if it's null with IngredientMinRange.HasValue
If it MinRange is an object:
IngredientMinRange = !string.IsNullOrEmpty(MinRange.ToString()) ? Convert.ToDouble(MinRange) : 0;

Assign null to decimal using ternary operator

I am using conversion to decimal of a byte array, such that it contains either null or any other number, stored in byte. The problem here is, when I try to convert a null to Nullable decimal, it converts it to zero. I want it to remain null...
Convert.ToDecimal(obj.sal== null ? null : System.Text.Encoding.ASCII.GetString(obj.sal))
If you want the result to potentially be null, then you shouldn't be calling Convert.ToDecimal - which always returns decimal. Instead, you should use:
x = obj.sal == null ? (decimal?) null
: Convert.ToDecimal(Encoding.ASCII.GetString(obj.sal));
Note that you have to cast the null literal to decimal? - or use some other form like default(decimal?) so that the type of the second operand is decimal? - otherwise the compiler won't be able to infer the type of the conditional expression. See this question for more details on that.
Because null is of type object (effectively untyped) and you need to assign it to a typed object.
x = obj.sal == null ? (decimal?) null
: Convert.ToDecimal(Encoding.ASCII.GetString(obj.sal));

C#.net can't assign null to a variable in an inline if statement

I was just wondering why the following code doesn't work (please keep in mind that I set age to be nullable):
myEmployee.age = conditionMet ? someNumber : null;
Yet the following works fine:
if(conditionMet)
{
myEmployee.age = someNumber;
}
else
{
myEmployee.age = null;
}
Why can't I set the value to null in a conditional operator?? All these if statements in my code is not nice.
Thanks.
The types on both sides have to be the same (or be implicitly convertible):
myEmployee.age = conditionMet ? someNumber : (int?)null;
From the docs:
Either the type of first_expression and second_expression must be the
same, or an implicit conversion must exist from one type to the other.
You can, just be clear about the type that null should be interpreted as:
myEmployee.age = conditionMet ? someNumber : (int?)null;
Look at what the documentation has to say:
[MSDN] The default value for a nullable type variable sets HasValue to false. The Value is undefined.
The default is thus null. Which means that you can simply do:
if (conditionMet)
myEmployee.age = someNumber;
There is no need for more obscure code syntax.
If required you can initialize it with null in advance, if it somehow was not the default, like so:
myEmployee.age = null;
if (conditionMet)
myEmployee.age = someNumber;
The types of the parts of the ternary statement must be implicitly castable to a common base. In the case of int and null, they aren't. You can solve this by making age a Nullable<int> (or int?) and casting someNumber to int?.
EDIT to clarify: you can set the value to null with a ternary statement with proper casting. The problem here isn't that you're trying to set a value to null with a ternary statement. It's that the compiler-inferred return types of the two expressions involved in the ternary statement cannot be implicitly casted to a common base type.

Is it right to cast null to nullable when using ternary expression assigning to a nullable type?

It feels strange to me to be casting null to a type so I wanted to double check that this is the right way to do this:
decimal? d = data.isSpecified ? data.Value : (decimal?)null;
NOTE: I am marking the answer that suggests the method that I personally like the best:
decimal? d = data.isSpecified ? data.Value : default(decimal?)
Yes, that's fine. Alternatives:
condition ? (decimal?) value : null
condition ? new decimal?(value) : null
condition ? value : default(decimal?)
condition ? value : new decimal?()
Pick whichever you find most readable.
There's nothing you can do outside the expression itself, as it's the type of the expression which the compiler doesn't know. For example, putting the whole expression in brackets and casting it wouldn't help.
Yes, it is perfectly fine.
Is data.Value of type decimal? If so, here's an alternative notation, without the cast:
decimal? d = data.isSpecified ? new decimal?(data.Value) : null;

Casting with conditional/ternary ("?:") operator

I have this extract of C# source code:
object valueFromDatabase;
decimal result;
valueFromDatabase = DBNull.Value;
result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0);
result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
The first result evaluation throws an InvalidCastException whereas the second one does not.
What is the difference between these two?
UPDATE: This question was the subject of my blog on May 27th 2010. Thanks for the great question!
There are a great many very confusing answers here. Let me try to precisely answer your question. Let's simplify this down:
object value = whatever;
bool condition = something;
decimal result = (decimal)(condition ? value : 0);
How does the compiler interpret the last line? The problem faced by the compiler is that the type of the conditional expression must be consistent for both branches; the language rules do not allow you to return object on one branch and int on the other. The choices are object and int. Every int is convertible to object but not every object is convertible to int, so the compiler chooses object. Therefore this is the same as
decimal result = (decimal)(condition ? (object)value : (object)0);
Therefore the zero returned is a boxed int.
You then unbox the int to decimal. It is illegal to unbox a boxed int to decimal. For the reasons why, see my blog article on that subject:
Representation and Identity
Basically, your problem is that you're acting as though the cast to decimal were distributed, like this:
decimal result = condition ? (decimal)value : (decimal)0;
But as we've seen, that is not what
decimal result = (decimal)(condition ? value : 0);
means. That means "make both alternatives into objects and then unbox the resulting object".
The difference is that the compiler can not determine a data type that is a good match between Object and Int32.
You can explicitly cast the int value to object to get the same data type in the second and third operand so that it compiles, but that of couse means that you are boxing and unboxing the value:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0);
That will compile, but not run. You have to box a decimal value to unbox as a decimal value:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0M);
The type of the operator will be object and in case the result must be 0 it will be implicitly boxed. But 0 literal is by default has int type so you box int. But with explicit cast to decimal you try to unbox it which is not permitted (boxed type must much with the one you cast back to). That is why you can get exception.
Here is an excerpt from C# Specification:
The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,
If X and Y are the same type, then this is the type of the conditional expression.
Otherwise, if an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the
conditional expression.
Otherwise, if an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the
conditional expression.
Otherwise, no expression type can be determined, and a compile-time error occurs.
Your line should be:
result = valueFromDatabase != DBNull.value ? (decimal)valueFromDatabase : 0m;
0m is the decimal constant for zero
Both parts of a conditional operator should evaluate to the same data type
The x : y part need a common type, the database's value is likely some kind of float and 0 is an int. This happens before the cast to decimal. Try ": 0.0" or ": 0D".
Unless I'm mistaken (which is very possible) its actually the 0 that's causing the exception, and this is down to .NET (crazily) assuming the type of a literal so you need to specify 0m rather than just 0.
See MSDN for more info.
There are two different types for the compiler to decide (at compile time) which one to cast to decimal. This it can't do.
Your answer would work if you combined both:
result = (decimal)(valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
At least, a similar situation casting into a parameter for me.

Categories

Resources