I suspect this has been done several times before, but on my way home this evening I considered what would be needed for the reverse of nullable value types - non-nullable reference types. I've had a play with an initial implementation in MiscUtil (not in the currently released version) and it basically boils down (after removing comments, equality etc) to this:
{
private readonly T value;
public NonNullable(T value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
this.value = value;
}
public T Value
{
get
{
if (value == null)
{
throw new NullReferenceException();
}
return value;
}
}
public static implicit operator NonNullable<T>(T value)
{
return new NonNullable<T>(value);
}
public static implicit operator T(NonNullable<T> wrapper)
{
return wrapper.Value;
}
}
Currently I've got both conversion operators as implicit, which isn't quite as safe/obvious as it is with nullable value types, but it does make life simpler. Obviously this is experimental code more than anything else, so I may change my mind later.
The simple use case is something like this (along with testing error cases):
public void Demo()
{
SampleMethod("hello"); // No problems
try
{
SampleMethod(null);
Assert.Fail("Expected exception");
}
catch (ArgumentNullException)
{
// Expected
}
try
{
SampleMethod(new NonNullable<string>());
Assert.Fail("Expected exception");
}
catch (NullReferenceException)
{
// Expected
}
}
private static void SampleMethod(NonNullable<string> text)
{
// Shouldn't get here with usual conversions, but could do
// through default construction. The conversion to string
// will throw an exception anyway, so we're guaranteed
// that foo is non-null afterwards.
string foo = text;
Assert.IsNotNull(foo);
}
I don't intend to use this within MiscUtil at the moment. Note that it's a struct, which has a few implications:
- It has the same memory footprint as the normal reference type. No GC pressure and no extra dereferencing. This is basically the main reason for making it a struct.
- It ends up being boxed to a new object. Boo hiss - ideally the boxing conversion would box it to the wrapped reference, and you could "unbox" (not really unboxing, of course) from a non-null reference to an instance of the struct.
- It's possible to create instances wrapping null references, by calling the parameterless constructor or using the default value of fields etc. This is very annoying.
The good news is that it's self-documenting and easy to use - the conversions will happen where required, doing appropriate checking (reasonably cheaply). The bad news is the lack of support from either the CLR (boxing behaviour above) or language (I'd love to specify string! text
as the parameter in the sample method above.) I suspect that if Microsoft were to do this properly, they'd want to avoid all of the problems above - but I'm not sure how...
Anyway, just a little experiment, but an interesting one - any thoughts?
Source Click Here.
No comments:
Post a Comment
Post your comments here: