Pregunta

Have you ever faced the need of informing anyone who uses your code and passes some reference typed parameters to not pass the null? You definitely have. And you should have thrown exceptions for each "bad" variable your code cannot work with.

Now, let's imagine you have created this struct:

public struct NotNullable<T> where T : class
{
    // Backing field for the value. Guaranteed to return not null.
    private T _value;
    public T Value
    {
        get
        {
            if (_value == null)
                throw new ApplicationException("Value is not initialized.");

            return _value;
        }
    }

    // Easy both-ways convertible.
    public static implicit operator T(NotNullable<T> notNullable)
    {
        return notNullable.Value;
    }
    public static implicit operator NotNullable<T>(T value)
    {
        return new NotNullable<T>(value);
    }

    // These members are overridden.
    public override string ToString()
    {
        return Value.ToString();
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        if (obj is NotNullable<T>)
        {
            return Value.Equals(((NotNullable<T>)obj).Value);
        }

        return Value.Equals(obj);
    }

    public NotNullable(T value)
    {
        this._value = value;
    }
}

Usage of such a structure:

class Program
{
    static void Main(string[] args)
    {
        NotNullable<string> a = "Hello World!";

        Console.WriteLine(a);
        Console.WriteLine((string)a);
        Console.WriteLine((object)a);
        Console.WriteLine((NotNullable<string>)a);

        // Produces fine outputs.


        var b = default(NotNullable<string>); 
        Console.WriteLine(b); // Throws an exception of non-initialized field.
    }
}

You could also make your methods to receive non-nullable reference typed parameters:

List<Tree> treeList;

public void CreateTree(NotNullable<Tree> tree)
{
    // Assume you cannot have the list contain nulls.
    treeList.Add(tree); // No null-checks required.
}

What could possibly be wrong in a such useful opposite to Nullable<> struct?

¿Fue útil?

Solución

I fail to see how this is advantageous to throwing ArgumentNullException. As the matter of fact, I'd rather do this:

public void Foo(MyClass item, MyClass2 item2)
{
    if (item == null)
        throw new ArgumentNullException("item");

    if (item2 == null)
        throw new ArgumentNullException("item2");
}

This way I let the programmer know which parameter was bad. With NotNullable<T> I imagine it would look like this:

public void Foo(NotNullable<MyClass> item, NotNullable<MyClass> item2) { ... }

Foo((NotNullable<MyClass>)myVar1, (NotNullable<MyClass2>)myVar2);

Now I get "Value is not initialized." thrown in my face. Which one?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top