2013-08-08 6 views
2

У вас когда-либо было столкнулось с необходимостью информирования всех, кто использует ваш код, и передает некоторые ссылочные типизированные параметры на не пропускает нуль? У тебя определенно есть. И вы должны были исключить исключения для каждой «плохой» переменной, с которой ваш код не может работать.Что делать, если вы можете создать ссылочный тип с нулевым значением?

Теперь давайте представим, вы создали эту структуру:

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; 
    } 
} 

Использование такой структуры:

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. 
    } 
} 

Вы можете также сделать свои методы, чтобы получить ненулевое эталонные типизированных параметров:

List<Tree> treeList; 

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

Что может быть неправильным в такой полезной противоположности Nullable<> struct?

+4

Как ваше исключение, не инициализированное, отличное от исключения с нулевой ссылкой? – asawyer

+1

В этом нет ничего плохого, однако ваша реализация должна быть изменена: исключение должно быть выбрано при создании * экземпляра 'NotNullable', а не при доступе к' Value'. Потому что в этом случае * ваш * код не генерирует исключение. Это код потребителя, и он несет ответственность за передачу ненулевого значения. –

+0

@asawyer в моем примере добавления параметра в 'List' не будет исключений для нулевой ссылки. – AgentFire

ответ

3

Я не вижу, как это выгодно бросать ArgumentNullException. На самом деле, я бы предпочел:

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

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

Таким образом, я дал возможность программисту узнать, какой параметр был плохим. С NotNullable<T> Я думаю, это будет выглядеть следующим образом:

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

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

Теперь я получаю "Value is not initialized." брошено в лицо. Который из?

+0

Изменить 'Foo ((NotNullable ) myVar1, (NotNullable ) myVar2);' to 'Foo (mayVar1, myVar2);'. – AgentFire

+0

Вы можете объяснить, какая переменная типа null. Подобно '' Значение типа MyClass не инициализируется. "'. – AgentFire

+0

Итак, если я предоставляю .dll для кого-то другого, его проект должен преобразовать все его типы в 'NotNullable'? – Artless