There have been many questions around support for non-nullable reference types in .NET. The great hope was code contracts, but it is limited to runtime checking for those who have limited budget.
As for approaches other than Code Contracts, Jon Skeet wrote a blog post about this a few years ago, and one of the commenters provided a useful looking NonNull struct that had the IL modified to disable the default constructor. This seems like an excellent approach, and I can imagine extending it to provide all sorts of non-nullable microtypes. The IL manipulation could be a post-build step triggered by an attribute on the struct e.g.
//Microtype representing a non-zero age, so we want to disable the default ctor
[NoDefaultConstructor]
public struct Age
{
public Age(int age)
{
// Implementation (including validation) elided
}
}
Before I investigate this further it I'd like to ask if anyone knows of any problems this might cause? I haven't been able to think of any.
This can be defeated quite easily - the run-time doesn't try to call the parameterless constructor of a struct (if present) in every scenario.
In particular, it won't get called when creating an array of the struct-type.
Age[] ages = new Age[3];
// This guy skips your "real" ctor as well as the "invalid" parameterless one.
Age age = ages[0];
...or in default(structType)
expressions:
// Invalid state here too.
Age age = default(Age);
From Jon Skeet's empirical research into this stuff, here's a list of other operations that don't call the constructor:
- Just declaring a variable, whether local, static or instance
- Boxing
- Using
default(T)
in a generic method- Using
new T()
in a generic method
Now the situation that leaves you in is that you have to somehow test for every Age
instance whether or not the instance was created by working around your fence - which isn't much better than not having erected the fence in the first place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With