Null coalescing operator on decimal and decimal - c#

I'm facing the following error while applying a null coalescing operator.
private decimal _currentImpulseId;
// ... later on used in public property getter as follows
public decimal CurrentImpulseId
{
get { return _currentImpulseId ?? 0M; }
set { _currentImpulseId = value; }
}
Following error is returned:
Operator '??' cannot be applied to operands of type 'decimal' and
'decimal'
Why doesn't this work? Does the null coalescing operator not work with decimals or am I missing something here? I know how I can work around this without using the operator, but this somewhat baffled me so I wonder if you know the correct answer on this?
Thanks!

You are getting this error because decimal is a value type, not a nullable value type (e.g. decimal?) or a reference type.
From MSDN:
...and is used to define a default value for nullable value types or reference types
The default value of a variable of type decimal is zero, so I am not quite sure why you would want to use this operator in this scenario.
Also, the backing field variable (_currentImpulseId) is not required as of .NET 3.0, since the introduction of auto-implemented properties means you can just write
public decimal CurrentImpulseId { get; set; }

Because decimal is a value type see HERE, you have to make it nullable.
Try
private decimal? _currentImpulseId;
// ... later on used in public property getter as follows
public decimal? CurrentImpulseId
{
get { return _currentImpulseId ?? 0M; }
set { _currentImpulseId = value; }
}

Related

Difference between "default" and "default!" in C#

On this particular page of documentation to do with record types. I noticed on the second example of code that the keyword default was used with the null forigiving operator. The example is shown below:
public record Person
{
public string FirstName { get; init; } = default!;
public string LastName { get; init; } = default!;
};
To my knowledge, the default value for a string type should be null. But if there is a null forgiving operator appended to the default operator, what does it actually do?
Does it make an empty string or is it still null?
! is null-forgiving operator. docs.microsoft
"Available in C# 8.0 and later, the unary postfix ! operator is the null-forgiving, or null-suppression, operator. In an enabled nullable annotation context, you use the null-forgiving operator to declare that expression x of a reference type isn't null: x!."

Implicit operator isn't called for default of struct in C#

I'm implementing a C# variant of Haskell's Maybe and came across a weird issue where null and default has different implication on the value returned from an implicit conversion.
public class TestClass
{
public void Test()
{
Maybe<string> valueDefault = default;
Maybe<string> valueNull = null;
Maybe<string> valueFoobar = "foobar";
Console.WriteLine($"Default: (Some {valueDefault.Some}, None {valueDefault.None}");
Console.WriteLine($"Null: (Some {valueNull.Some}, None {valueNull.None}");
Console.WriteLine($"Foobar: (Some {valueFoobar.Some}, None {valueFoobar.None}");
}
}
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None { get; private set; }
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>() {
Some = value,
None = value == null
};
}
}
The output being:
Default: (Some , None False)
Null: (Some , None True)
Foobar: (Some foobar, None False)
I was expecting both valueDefault and valueNull to be equal. But seems that null is converted while default isn't. I fixed the issue by replacing None with HasSome with a reversed boolean condition, but still the question remains.
Why is null and default treated differently?
Every type has a default value, including Maybe<T>. See this page for a list.
Maybe<string> valueDefault = default; will assign the default value of Maybe<string> to valueDefault. What's the default value of Maybe<string>? According to that page, since Maybe<string> is a struct, its default value is:
The value produced by setting all value-type fields to their default values and all reference-type fields to null.
So it's an instance of Maybe<string> with Some being null and None being false. false is the default value of bool.
The compiler doesn't try to use the default value of string, since that requires a further conversion to Maybe<string>. If it can just use the default value of Maybe<string>, why go the extra trouble, right?
You can force it to though:
Maybe<string> valueDefault = default(string);
null, on the other hand, gets converted to Maybe<string> because null is not a valid value of Maybe<string> (structs can't be null!), so the compiler deduces that you must mean null as string, and does the implicit conversion.
You might know this already, but you seem to be reinventing Nullable<T>
default always fills the memory of the struct with zero bytes. null is not a valid value for a value type, so the compiler discovers the implicit (Maybe<string>)(string)null cast.
Perhaps you could replace with;
public struct Maybe<T>
{
public T Some { get; private set; }
public bool None => Some == null;
...

What are Nullable Types in C#?

int? _fileControlNo = null;
public int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
I'm getting a syntax error when I assign null values to the above properties.
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? null : Convert.ToInt32(sArrElements.Value(3));
Please, can anyone explain to me why the error occurs if I'm able to set null value in valuetype object using Nullable Type.
The results of the conditional operators need to be of the same type or types that can be implicitly convertible to each other.
In your case you have a null and an Int32 - these violate that requirement.
If instead of an Int32 you return a nullable Int32, the null can be implicitly converted to this type and your code will work (or alternatively, cast the null to an int?).
Cast your null to int?
objDPRUtils.FileControlNo =sArrElements.Value(3)==null ? (int?) null : Convert.ToInt32(sArrElements.Value(3));
The conditional operator needs to return result of the same type and in your case its not possible for null
this should work
sArrElements.Value(3)==null ? (int?)null : Convert.ToInt32(sArrElements.Value(3));
Nullable types are exactly what they say they are: simple value types that can also store a null value.
I would suggest that you do not need the last line of code at all. you should be able to get away with:
objDPRUtils.FileControlNo =sArrElements.Value(3);
If you really want to assign another value in case of null, use the null coalescing operator ??
objDPRUtils.FileControlNo =sArrElements.Value(3)??0;
which in this case, would assign the value 0 to the FileControlNo in case of the right hand side being null.
Try to assign directly like this :
objDPRUtils.FileControlNo =sArrElements.Value(3);
Your code mixes types null and Int32 cannnot be mixed in this instance like that. They need to be of the same type.
If you use int.TryParse and only attempt to set the value on success you will achieve the same result and can use HasValue on the field to determine if its null or not which is how nullable types are used typically
Silly example
class Program
{
private static int? _fileControlNo;
static void Main(string[] args)
{
string[] sArrElements = new string[] { "1", "2", "3", null };
int result;
if (int.TryParse(sArrElements[3], out result))
{
FileControlNo = result;
}
if (_fileControlNo.HasValue)
{
// do something here
}
}
public static int? FileControlNo
{
get { return _fileControlNo; }
set { _fileControlNo = value; }
}
}
you will note that your code inside the test for HasValue in this case will never execute because _fileControlNo cannot be set because tryParse always fails (change the indexer and that will change).

How to convert the following decimal? to String("F2")

I have Decimal? Amount
In my model I have a value as #item.Sales, which I`m trying to write as #item.Sales.ToString("F2").
I`m having the message error Error 1 No overload for method 'ToString' takes 1 arguments
How can I achieve the above
If it's a nullable decimal, you need to get the non-nullable value first:
#item.Sales.Value.ToString("F2")
Of course, that will throw an exception if #item.Sales is actually a null value, so you'd need to check for that first.
You could create an Extension method so the main code is simpler
public static class DecimalExtensions
{
public static string ToString(this decimal? data, string formatString, string nullResult = "0.00")
{
return data.HasValue ? data.Value.ToString(formatString) : nullResult;
}
}
And you can call it like this:
decimal? value = 2.1234m;
Console.WriteLine(value.ToString("F2"));
if( item.Sales.HasValue )
{
item.Sales.Value.ToString(....)
}
else
{
//exception handling
}
Use the unary ? operator to run .ToString() only when there's an object
#item.Sales?.ToString("F2")
Or use the double ?? operator thus makes it non-nullable:
#((item.Sales??0).ToString("F2"))
This is better than #item.Sales.Value.Tostring("F2") because if you don't check for null value before using .ToString("F2") the code will break at runtime.

? (nullable) operator in C# [duplicate]

This question already has answers here:
What is the purpose of a question mark after a value type (for example: int? myVariable)?
(9 answers)
Closed 5 years ago.
What is changed by applying nullable Operator on value type datatype that now it can store null.
As others have said, "?" is just shorthand for changing it to Nullable<T>. This is just another value type with a Boolean flag to say whether or not there's really a useful value, or whether it's the null value for the type. In other words, Nullable<T> looks a bit like this:
public struct Nullable<T>
{
private readonly bool hasValue;
public bool HasValue { get { return hasValue; } }
private readonly T value;
public T value
{
get
{
if (!hasValue)
{
throw new InvalidOperationException();
}
return value;
}
}
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
// Calling new Nullable<int>() or whatever will use the
// implicit initialization which leaves value as default(T)
// and hasValue as false.
}
Obviously in the real code there are more methods (like GetValueOrDefault()) and conversion operators etc. The C# compiler adds lifted operators which effectively proxy to the original operators for T.
At the risk of sounding like a broken record, this is still a value type. It doesn't involve boxing... and when you write:
int? x = null;
that's not a null reference - it's the null value of Nullable<int>, i.e. the one where hasValue is false.
When a nullable type is boxed, the CLR has a feature whereby the value either gets boxed to a null reference, or a plain boxed T. So if you have code like this:
int? x = 5;
int y = 5;
object o1 = x;
object o2 = y;
The boxed values referred to by o1 and o2 are indistinguishable. You can't tell that one is the result of boxing a nullable type.
The ? syntax is syntactic sugar to the Nullable<T> struct.
In essence, when you write int? myNullableInt, the compiler changes it to Nullable<int> myNullableInt.
From MSDN (scroll down to "Nullable Types Overview"):
The syntax T? is shorthand for Nullable, where T is a value type. The two forms are interchangeable.
Nothing is changed on the value type itself, it's simply wrapped in a System.Nullable<T> struct.
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx
The type changes from what it used to be to a Nullable type.
If you had an int, and decided to make it an int?:
int myInt;
And you make it:
int? myInt;
it is now:
Nullable<int> myInt;
In reality.
In basic terms, a nullable type is a boxed version of the normal type that has an extra boolean field called hasValue on it.
When this field is set to false, then the instance is null.
Check out this answer for a bit more detail on the CLR implementation, and why they might have chosen it: Boxing / Unboxing Nullable Types - Why this implementation?

Categories

Resources