When I program in Java, I make all nullability explicit; that is, an instance of Foo is assumed to be non-null, and if I want it to be null, I use a @Nullable
annotation (or better, Optional<Foo>
). But C# doesn't natively support annotations, and Nullable<> is only for value types.
But what if I did something like this?
struct Value<T> where T : class {
T value;
}
And then use Value<Foo>?
as the type for a field. What impact would this have on performance/memory, and is there something that makes this a very bad idea?
3 Answers 3
References are already passed by value in .net. And since value
can be null, you’re not gaining much. You can’t even force a nice constructor to guarantee that value is non-null since structs require a public nullary constructor.
You’re doing work to gain nothing but confusion.
-
I think that's a little bit unfair. Using such a
NonNullable
is making a declaration of intent that draws attention at compile-time (rather than at runtime), making it a bit more effective than an assertion. It's trivial to work around, but such work-arounds tend to be deliberate. Avoiding use of the public constructor of the struct can be enforced by both a preprocessor and by a coding convention. That said, I don't think it's usually worth the trade-offs; I favor coding contracts over this, and even that's not probably only worth it for completely new code-bases.Brian– Brian2017年11月07日 14:11:07 +00:00Commented Nov 7, 2017 at 14:11 -
@Brian - I disagree. Preprocessors and coding conventions are fragile. More likely, someone new to the project will go about their day assuming that the value can never be null, causing bugs. Or your serialization breaks because of the stupid wrapper.Telastyn– Telastyn2017年11月07日 15:59:34 +00:00Commented Nov 7, 2017 at 15:59
-
And in that scenario (assuming you use Jon skeet's implementation of non-nullable), you'll hit a run-time exception, which is the same behavior you'd experience when using a non-nullable. So the error scenario is the same. As for serialization: You're right that non-nullables make serialization more complicated.Brian– Brian2017年11月08日 14:27:16 +00:00Commented Nov 8, 2017 at 14:27
There are few C# Option
/Maybe
implementations : here, here or here
There is also a proposal to make non-nullable references in C#, in which case there will be need for some kind of Nullable/Option type for reference types.
So your idea is perfectly sound and supported by many people. Its just your implementation is not that great. You don't need to wrap a reference in structure and then use Nullable
. Just make the structure behave like Nullable
. Which is what all other implementations are doing.
As for performance, I wouldn't worry too much. Better performance is often achieved using better structures and algorithms and not micro-optimizing your types. And any performance hit will be out-weighted by improved stability and readability of your code, due to explicit handling of null
states.
Looks like you're reinventing wheels there - why can't you simply use T?
as the nullable value type? I imagine under the covers exactly what you are suggesting is happening already. As the nullability is explicitly defined in the type definition using the ?, then you have what you want already.
As for types that are already nullable, I'd say making a nullable generic type that can itself contain a null to be a particularly bad idea just because it will confuse people, add lots of extra code and provide no benefit.
If you really must have an annotation, use a naming convention.
-
I can't use
T?
because T is a reference type; it's an abstract class with subclasses.Nick Tobey– Nick Tobey2017年11月05日 00:32:36 +00:00Commented Nov 5, 2017 at 0:32
MiscUtil.NonNullable<T>
, available at jonskeet.uk/csharp/miscutil . I would encourage you to read the source code (including the comments) withinNonNullable.cs
; it handles numerous scenarios that you may not have considered.