Reputation: 424
The following does not compile:
public struct Foo
{
public static implicit operator Foo(string bar)
{
return new Foo();
}
public static implicit operator Foo(long? bar)
{
return new Foo();
}
public static void Test()
{
Foo bar = 0;
Foo bar2 = (long?)null;
Foo bar3 = "";
Foo bar4 = null; // Cannot convert null to 'Foo' because it is a non-nullable value type
}
}
'Foo bar4 = null' fails, presumably because the compiler doesn't know which implicit operator to use, because changing the operator from long? to long causes that line to compile but instead 'Foo bar2 = (long?)null' fails instead (requiring an explicit cast).
My question is; Is there a way to make 'Foo bar4 = null' work as well, or is this just a limitation of the language (that I cannot add a 'null' operator or tell it which one to use for null for instance)?
I realize I could change the struct to a class, but I don't want it to be null, I want to be able to have null create an instance of it.
EDIT: I should add that I understand there are a lot of ways to get around this, but since '= null' (doing 'new Foo()' essentially) works with only one of the implicit operators, I'm just wondering if it's possible to have it still work with both of them there (I feel like there should be a way in the language to do this - either now or in the future, no?).
Upvotes: 1
Views: 1539
Reputation: 21729
My question is; Is there a way to make 'Foo bar4 = null' work as well, or is this just a limitation of the language (that I cannot add a 'null' operator or tell it which one to use for null for instance)?
Based on this question and your edit, you are basically asking
Why does
Foo bar4 = null
compile when it does not if I add another implicit cast operator?
The answer is simple. null
without any context is typeless and so the compiler does not know which operator to use. Why? Well the overload resolution algorithm underpinning the language does not examine the type of the thing you are trying to assign null
to, so it doesn't know which operator you intended.
You could argue that a future language spec could be modified to do this extra analysis, but the team probably considers that not worth the effort or it would be a breaking change.
The best that you can do is to avoid the casting in this case. You can, depending on your C# level, do either of these:
Foo bar4 = default;
Foo bar4 = default(Foo);
which results in a useable Foo
. The two default expressions and new Foo()
are all equivalent. They all result in a struct with all its fields zeroed out.
For more information you can see the default value expressions section of the C# programming guide.
And finally, while you can get away with a single implicit cast operator that casts a null
to a struct, it doesn't mean you should. Someone reading that code not knowing about the cast would probably be questioning their sanity for a few minutes. It's best not to stray from idiomatic code if you can.
Upvotes: 3
Reputation: 885
If I'm not mistaken, a struct can never be assigned a value of null because it's a value-type, similar to int
, bool
, and DateTime
.
You could, however, use a Nullable<T> like so:
Foo? bar4 = null;
or
Nullable<Foo> bar4 = null;
Make sure you treat it like any other Nullable<T> and check .HasValue
before referencing bar4.Value
to avoid the wonderful NullReferenceException.
Upvotes: 0
Reputation: 37095
Your struct isn´t nullable because you introduce a cast that enables to cast a null-value to that type. A cast in itself is just a member that doesn´t change the types semantics.
In fact a struct
by itself is never null, however references to it may be, but only when they are of type Nullable<Foo>
. So bar4
needs to be of type Foo?
, which is the same as Nullable<Foo>
.
Upvotes: 2