Есть ли какие-либо серьезные основания, почему ternaries в C# ограничены?

Когда я был молод, я слышал это: хороший хакер должен быть опытным в 4 редакторах и 4 языках.

И приняли его близко к сердцу с тех пор....

я обычно использую vi (m), (x) emacs, затмение, sed/awk/perl (да.. они - текстовые редакторы).

, по моему скромному мнению, осваивая диапазон инструментов важно. Нужно подвергнуть его мозг для перемещения из зоны комфорта время от времени.

я теперь нашел это удивительным, что я имею сотни сочетаний клавиш в кончике пальца и редко ввожу сочетание клавиш одного в другой.

9
задан Austin Salonen 3 November 2009 в 19:31
поделиться

4 ответа

использование:

object o = ((1==2) ? (object)1 : "test");

Проблема в том, что тип возвращаемого значения условного оператора не может быть однозначно определен. То есть между int и string нет лучшего выбора. Компилятор всегда будет использовать тип истинного выражения и при необходимости неявно преобразовать ложное выражение.

Изменить: Во втором примере:

int? subscriptionID; // comes in as a parameter

EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
    Value = subscriptionID.HasValue ? (object)subscriptionID : DBNull.Value,
}

PS:
Это не называется «тернарным оператором». Это тернарный оператор, но он называется «условным оператором».

17
ответ дан 4 December 2019 в 06:49
поделиться

Почему функция X работает таким образом, часто бывает очень сложным вопросом. Намного легче ответить на реальное поведение.

Мое обоснованное предположение относительно того, почему. Условный оператор может кратко и лаконично использовать логическое выражение для выбора между двумя связанными значениями. Они должны быть связаны, потому что они используются в одном месте. Если вместо этого пользователь выбирает 2 несвязанных значения, возможно, в коде есть небольшая опечатка / ошибка, и компилятору лучше предупредить его об этом, чем неявно преобразовывать его в объект. Возможно, они этого не ожидали.

2
ответ дан 4 December 2019 в 06:49
поделиться

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

Во-первых, желательно, чтобы как можно больше выражений имели однозначный тип, который может быть определен исключительно по содержимому выражения. Это желательно по нескольким причинам. Например: это значительно упрощает создание движка IntelliSense. Вы вводите xM (some-expression. , и IntelliSense должна иметь возможность анализировать some-expression , определять его тип и создавать раскрывающийся список ДО того, как IntelliSense узнает, на какой метод ссылается xM. IntelliSense не могу знать, что такое x. M наверняка ссылается на то, что M перегружен, пока не увидит все аргументы, но вы еще не ввели даже первый аргумент.

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

void M(object x) {}
void M(int x) {}
void M(string x) {}
...
M(b ? 1 : "hello");

Что это должно делать? Должен ли он вызывать перегрузку объекта? Должен ли он иногда вызывать перегрузку строки, а иногда - перегрузку int? Что, если бы у вас была другая перегрузка, скажем M (IComparable x) - когда вы ее выберете?

Ситуация становится очень сложной, когда информация о типе «течет в обе стороны». Высказывание «Я назначаю эту вещь переменной типа object, поэтому компилятор должен знать, что можно выбрать объект, поскольку тип» не стирается; Это' Часто бывает, что мы не знаем тип переменной, которую вы назначаете, потому что это то, что мы пытаемся выяснить . Разрешение перегрузки - это как раз процесс определения типов параметров, которые являются переменными, которым вы назначаете аргументы, из типов аргументов. Если типы аргументов зависят от типов, которым они назначаются, то наши рассуждения замкнуты.

Информация о типах действительно "течет в обе стороны" для лямбда-выражений; На ее эффективное внедрение у меня ушло почти год. Я' он написал длинную серию статей, описывающих некоторые трудности в разработке и реализации компилятора, который может выполнять анализ, когда информация о типе перетекает в сложные выражения в зависимости от контекста, в котором выражение, возможно, используется; первая часть находится здесь:

http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx

Можно сказать " Хорошо, хорошо, я понимаю, почему тот факт, что я назначаю объекту, не может быть безопасно использован компилятором, и я понимаю, почему необходимо, чтобы выражение имело однозначный тип, но почему тип объекта выражения не , поскольку как int, так и string можно преобразовать в объект? " Это подводит меня к моему третьему пункту:

В-третьих, одним из тонких, но последовательно применяемых принципов проектирования C # является "не надо"

Причина этого проектного решения заключается в том, что обычным людям легче понять, что компилятор собирается делать в любой данной ситуации, когда необходимо определить лучший тип; если вы знаете, что будет выбран тип, который прямо здесь, глядя вам в лицо, тогда будет намного проще понять, что произойдет.

Это также избавляет нас от необходимости разрабатывать множество сложных правил о том, какой самый общий тип набора типов в случае конфликтов. Предположим, у вас есть типы {Foo, Bar}, где оба класса реализуют IBlah, и оба класса наследуются от Baz. Какой наиболее распространенный тип, IBlah, который реализуется обоими, или Baz, который расширяется? Мы не хотим отвечать на этот вопрос; мы хотим полностью этого избежать.

Наконец, Я отмечаю, что компилятор C # на самом деле в некоторых неясных случаях получает некорректное определение типов. Моя первая статья об этом находится здесь:

http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx

Можно утверждать, что на самом деле компилятор делает это правильно, а спецификация неверна; проект реализации, на мой взгляд, лучше, чем проект спецификации.

В любом случае, это всего лишь несколько причин для разработки этого конкретного аспекта тернарного оператора. Здесь есть и другие тонкости, например, как верификатор CLR определяет, гарантированно ли данный набор путей ветвления оставит правильный тип в стеке на всех возможных путях. Обсуждение этого в деталях уведет меня довольно далеко.

//blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx

Можно утверждать, что на самом деле компилятор делает это правильно, а спецификация неверна; дизайн реализации, на мой взгляд, лучше, чем проект спецификации.

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

//blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx

Можно утверждать, что на самом деле компилятор делает это правильно, а спецификация неверна; проект реализации, на мой взгляд, лучше, чем проект спецификации.

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

d.

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

d.

В любом случае, это всего лишь несколько причин для разработки именно этого аспекта тернарного оператора. Здесь есть и другие тонкости, например, как верификатор CLR определяет, гарантированно ли данный набор путей ветвления оставит правильный тип в стеке на всех возможных путях. Обсуждение этого в деталях уведет меня довольно далеко.

15
ответ дан 4 December 2019 в 06:49
поделиться

«int» - это примитивный тип, а не объект, в то время как «строка» считается скорее «примитивным объектом». Когда вы делаете что-то вроде «object o = 1», вы фактически упаковываете «int» в «Int32». Вот ссылка на статью о боксе:

http://msdn.microsoft.com/en-us/magazine/cc301569.aspx

Как правило, бокса следует избегать из-за потери производительности, которую трудно отследить.

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

Заявление: объект o = ((1 == 2)? 1: "test");

Компилятор:

  1. Какие бывают типы "1" и "test" в '((1 == 2)? 1: "контрольная работа")'? Совпадают ли они?
  2. Совпадает ли последний тип из №1 с типом оператора присваивания для «объекта o»?

Поскольку компилятор не оценивает №2, пока не будет выполнен №1, он не работает.

0
ответ дан 4 December 2019 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: