Неявный оператор на универсальных типах
-
26-09-2019 - |
Вопрос
Есть ли что-то не так с использованием неявного оператора, как следующее:
//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;
}
}
Я думал, что я мог бы относиться к примеру объекта в качестве значения такого типа, но видя, как я никогда не видел пример этого, я думал, может быть, была причина нет сделать что-то подобное, что кто-то мог указать?
В моем фактическом коде я думал о том, чтобы сделать это как часть слоя абстракции данных, чтобы я мог бы вернуть объекты с информацией, описывающей основные данные, но позволяют логическому коду обрабатывать его в качестве типа, когда все его необходимо знать Это значение, и в то же время сохраняйте все это здорово и введите безопасным с двоиками.
Решение
Если все следующие верны:
все Возможные значения вашего
MyClass<T>
Тип (в том числеnull
Если это не тип значения!) Карта допустимого значенияT
неявный оператор никогда не бросает (даже не для
null
!)Неявное преобразование делает семантический смысл и не путает клиентский программист
Тогда в этом нет ничего плохого. Конечно ты мог Делайте любую из этих трех вещей, но это был бы плохой дизайн. В частности, неявный оператор, который бросает, может быть очень трудно отладить, потому что место, где он называется, не говорит о том, что он называется.
Например, считайте, что 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
пришли из!
Другие советы
Это отличный узор. Просто имейте в виду, что для того, чтобы использовать его как переменную типа T
, вы должны либо явно бросить его T
, или назначить его переменной типа T
. Отказ Катушка будет проходить автоматически в вызовах метода и другие вещи (например, ваш пример дополнения), который принимает T
.