неявный оператор на универсальных типах - PullRequest
8 голосов
/ 29 сентября 2010

Есть ли что-то не так с использованием неявного оператора, подобного следующему:

//linqpad c# program example
void Main()
{
    var testObject = new MyClass<int>() { Value = 1 };

    var add = 10 + testObject; //implicit conversion to int here
    add.Dump(); // 11
}

class MyClass<T>
{
    public T Value { get; set; }
    public static implicit operator T (MyClass<T> myClassToConvert)
    {
        return myClassToConvert.Value;
    }
}

Я думал, что мог бы таким образом рассматривать экземпляр объекта как тип значения, но, видя, я никогдавидел пример этого, я подумал, что, может быть, была причина , а не , чтобы сделать что-то подобное, на что кто-то мог бы указать?

В моем реальном коде я думал сделать это как частьслой абстракции данных, чтобы я мог возвращать объекты с информацией, описывающей лежащие в основе данные, но позволить логическому коду рассматривать его как тип значения, когда все, что ему нужно знать, - это значение, и в то же время сохранять все это приятным ивведите безопасный с генериками.

Ответы [ 2 ]

10 голосов
/ 29 сентября 2010

Если выполняются все следующие условия:

  • все возможные значения вашего типа MyClass<T> (включая null, если это не тип значения!) Соответствуют действительному значению T

  • неявный оператор никогда не выбрасывает (даже для null!)

  • неявное преобразование имеет смысловой смысл и не смущает клиента-программиста

тогда в этом нет ничего плохого. Конечно, вы могли бы сделать любую из этих трех вещей, но это был бы плохой дизайн. В частности, неявный оператор throw может быть очень сложным для отладки, потому что место, где он вызывается, не говорит, что он вызывается.

Например, предположим, что T? не имеет неявного преобразования в T (где T, конечно, тип значения). Если бы существовал такой неявный оператор, он должен был бы выдавать, когда T? равен нулю, поскольку нет очевидного значения для преобразования null в такое значение, которое имело бы смысл для любого типа значения T .


Позвольте мне привести пример, где у меня возникли проблемы при отладке проблемы, когда неявный оператор выдал:

public string Foo()
{
    return some_condition ? GetSomething() : null;
}

Здесь GetSomething вернул что-то типа, который я написал, который имеет неявное пользовательское преобразование в string. Я сделал абсолютно уверенным , что GetSomething никогда не сможет вернуть null, и все же я получил NullReferenceException! Зачем? Поскольку приведенный выше код не эквивалентен

return some_condition ? (string)GetSomething() : (string)null;

но до

return (string)(some_condition ? GetSomething() : (Something)null);

Теперь вы можете видеть, откуда взялся null!

1 голос
/ 29 сентября 2010

Отличная картина. Просто имейте в виду, что для того, чтобы использовать его как переменную типа T, вы должны либо явно привести его к T, либо присвоить его переменной типа T. Приведение будет происходить автоматически в вызовах методов и других вещах (таких как пример добавления), которые принимают T.

Неявное преобразование без присваивания?

...