Difference between "default" and "default!" in C# - 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!."

Related

Null-Forgiving operator still showing warning

I have the following method to override ToString()
public override string ToString()
{
if (HasNoValue)
return "No value";
return Value!.ToString();
}
If HasNoValue returns true, the value property contains null so "No Value" is returned.
The HasNoValue property (and HasValue) looks like this:
public bool HasValue => value != null;
public bool HasNoValue => !HasValue;
So if NoHasValue is false I know value is not Null. As you can see I've added the null-forgiving operator on the value property before the call to ToString()
I have Nullable enable within my project <Nullable>enable</Nullable>
However, I still receive the following warning:
Warning CS8603 Possible null reference return.
Why am I receiving this warning if I've added the null-forgiving operator?
The direct answer to your question is that Object.ToString() returns string?, so you need the null-forgiving operator at the end of the .ToString() call
You can use the MemberNotNullWhen attribute to tell the compiler that the Value property won't be null when the HasNoValue property is false
[MemberNotNullWhen(false, nameof(HasNoValue))]
public object? Value { get; set; }

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;
...

Implicit conversion from Nullable

I want to create a class like Nullable except for the moment that it could work with classes and structures:
public class MyWrapper<T>
{
public MyWrapper(T value)
{
Value = value;
}
public T Value { get; set; }
}
Then I want to add implicit conversion of Nullable to MyWrapper:
public static implicit operator MyWrapper<T> (Nullable<T> value)
{
return new MyWrapper<T>(value);
}
And of course, it fails because of Nullable restrictions:
Only non-nullable value type could be underlying of 'System.Nullable'
It is a pretty understandable error but in theory, I could convert any Nullable to MyWrapper, because of restrictions of Nullable harder than MyWrapper's restrictions.
So it there any workaround for Nullable to MyWrapper implicit conversion?
Why do I need to use MyWrapper for classes?
We use some sort of bad GraphQl on the backend and sent updation objects like this:
class UpdateProductRequest
{
public MyWrapper<string> Country {get;set;}
public MyWrapper<string> Title {get;set;}
}
So
new UpdateProductRequest
{
Title = "new title"
}
update the title, but not the country.
You can define implicit casting from underlying type to MyWrapper:
public static implicit operator MyWrapper<T> (T value)
{
return new MyWrapper<T>(value);
}
Now with such operator you can do this:
MyWrapper<int> w = new int?(5);
MyWrapper<int> w2 = (int?)null; //here casting method is not called
So initially the Nullable is casted down to the underlying type and then to MyWrapper. If it's null there is just null assignment to variable of typeMyWrapper which is class so it's valid. Nullable has special treatment by the compiler so it may look like a magic but it works.

what does question mark means in MVC?

what does "?" mean in MVC , when we write it with data type for example
public Grade? Grade { get; set; }
what does "?" shows? and what will be difference if i will not write "?" ?
If you want to make any property nullable then we add question marks "?"
public Grade? Grade { get; set; } --> Grade property will accept null value also.
public Grade Grade { get; set; } --> no null value allowed for this property
Grade? is the same as Nullable<Grade>. It's a C# language feature, not specific to MVC.
? represents a nullable type. Nullable types represent value-type variables that can be assigned the value of null. You cannot create a nullable type based on a reference type, because reference types already support null.
From the link you provided for your tutorial:
The Grade property is an enum. The question mark after the Grade type
declaration indicates that the Grade property is nullable. A grade
that's null is different from a zero grade — null means a grade isn't
known or hasn't been assigned yet
So, in the same example Enrollment is a reference type which, is nullable by default. So won't need explicit ? when declaring objects of that class.
This is a valid nullable declaration. You can assign null to it:
int? num = null;
You can also do a:
int y = num.GetValueOrDefault();
Where y will get whatever value num contains (if it contains a value), otherwise null which is default for nullable types.
You can expicitly check if it contains null by:
num.HasValue();
You get values out of nullable typed variables like this:
int y = num.value;
In the link you provided in the comments, Grade represents an enum which is a value type. Value types don't have the ability to point to null, so it needs to be suffixed with the ? symbol to represent a null value. It's essentially the same as saying:
public Nullable<Grade> Grade { get; set; }
More examples:
int a = null; //not allowed
int b? = null; //allowed
string refType = null; //allowed
int x? = 2;
int y? = 2;
Keep in mind that if you try to perform an operation on nullable types, the operators will be lifted:
book areEqual = x == y;
which translates to:
bool areEqual = (x.HasValue && y.HasValue) ? (x.Value == y.Value) : false;
That means that the nullable type can use the operators from the original value type.
The id may be null while passing as a parameter to action method.

Null coalescing operator on decimal and decimal

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; }
}

Categories

Resources