Нередко в моих программах на C# возникает необходимость уточнить тип переменной, то есть попросить компилятор посчитать, что тип переменной не тот, что объявлен, а один из базовых.
Рассмотрим на примере. Допустим, имеется группа методов:
void M(IReadOnlyList<int> x) { } // 2
void M(IList<string> x) { } // 3
void M(IReadOnlyList<string> x) { } // 4
И нам…
// …необходимо вызвать второй из них, принимающий: IReadOnlyList<int>.
}
Что мы обычно делаем? Применяем оператор приведения типа:
M((IReadOnlyList<int>)x);
}
Этот способ мне очень не нравится. Дело в том, что такой синтаксис похож на синтаксис приведения типа (хотя, фактически, никаких лишних инструкций тут не будет) и при просмотре большого количества кода этот вызов не сложно перепутать со следующим:
M((IReadOnlyList<string>)x);
}
который успешно скомпилируется, но, скорее всего, не будет работать, приводя к InvalidCastException. При чтении кода к приведениям типов всегда нужно относиться внимательно - это места, в которых не редко случаются ошибки.
Можно обойтись и без приведения типа:
IReadOnlyList<int> y = x;
M(y);
}
Это несколько многословно, но мне кажется самым лучшим решением - максимально понятно и эффективно.
В более синтаксически продвинутых языках, например в Nemerle, для подобных случаев существует специальный оператор статического приведения типа, синтаксис которого отличается от обычного приведения - вот это было бы очень полезно иметь и в C# (а заодно уж, и отдельный оператор для боксинга-анбоксинга не помешал бы, ну да чего уж :о). Вот как применение этого оператора могло бы выглядеть:
M(x : IReadOnlyList<int>);
}
Кажется, тут очевидно, что имеется в виду именно уточнение (двоеточие) - считать в данном случае, что переменная x имеет тип IReadOnlyList<int>.
Так вот, как [внезапно] вдруг оказалось, такой оператор в C# уже давно есть! Посмотрите:
M(x ?? default(IReadOnlyList<int>));
}
И всё. Достаточно использовать null-coalescing operator. Единственное, чем использование этого оператора в данном случае грозит - более сложным IL. Но и тут имеется перспектива - должно быть не сложно добавить в компилятор оптимизацию: в случае, когда про выражение в правой части оператора (то, что после ??) можно на этапе компиляции сказать, что оно всегда null, а это можно совершенно определённо сказать о выражении default здесь:
A default-value-expression is a constant expression (§7.19) if the type is a reference type or a type parameter that is known to be a reference type (§10.1.5).
- никакой специльной логики генерировать не нужно - правая часть на значение результата не повлияет.
Теперь попробую использовать для уточнения типа null-coalescing operator, посмотрим, через какое-то время, к чему это приведёт.
Оператор default имеет совсем другую семантику, так что такой код соберет при чтении много пожеланий его автору :)
ОтветитьУдалитьЭто, в первую очередь, и смущает - с непривычки, кажется, ищешь додвох, а его нет.
ОтветитьУдалитьИдея с дефолтом пришла только вчера и сегодня вчерашний код неприязни не вызвал :о) Интересно посмотреть, что будет через полгодика :о)