example - ternary operator java



Разница между C#и тернарным оператором Java(?:) (4)

Я новичок в C # и столкнулся с проблемой. Существует разница между C # и Java при работе с тернарным оператором ( ? : .

В следующем фрагменте кода почему 4-я строка не работает? Компилятор показывает сообщение об ошибке, there is no implicit conversion between 'int' and 'string' . 5-я строка не работает так же хорошо. Оба List являются объектами, не так ли?

int two = 2;
double six = 6.0;
Write(two > six ? two : six); //param: double
Write(two > six ? two : "6"); //param: not object
Write(two > six ? new List<int>() : new List<string>()); //param: not object

Тем не менее, тот же код работает в Java:

int two = 2;
double six = 6.0;
System.out.println(two > six ? two : six); //param: double
System.out.println(two > six ? two : "6"); //param: Object
System.out.println(two > six ? new ArrayList<Integer>()
                   : new ArrayList<String>()); //param: Object

Какая языковая функция в C # отсутствует? Если есть, то почему это не добавлено?


Answer #1

Данные ответы хороши; Я бы добавил к ним, что это правило C # является следствием более общего руководства по проектированию. Когда C # получает запрос на вывод типа выражения из одного из нескольких вариантов, он выбирает лучший из них . То есть, если вы дадите C # несколько вариантов выбора, таких как «Жираф, Млекопитающее, Животное», тогда он может выбрать наиболее общий - Животное - или он может выбрать самый конкретный - Жираф - в зависимости от обстоятельств. Но он должен выбрать один из вариантов, которые ему фактически дали . C # никогда не говорит «мой выбор между Cat и Dog, поэтому я сделаю вывод, что Animal - лучший выбор». Это не был выбор, поэтому C # не может выбрать его.

В случае троичного оператора C # пытается выбрать более общий тип int и string, но ни один из них не является более общим типом. Вместо того, чтобы выбирать тип, который изначально не был выбран, например, объект, C # решает, что никакой тип не может быть выведен.

Отмечу также, что это соответствует другому принципу разработки C #: если что-то выглядит не так, сообщите об этом разработчику. Язык не говорит: «Я собираюсь угадать, что ты имел в виду, и запутаться, если смогу». Язык говорит: «Я думаю, что вы написали здесь что-то непонятное, и я расскажу вам об этом».

Кроме того, я отмечаю, что C # не ведет от переменной к назначенному значению , а наоборот. C # не говорит: «Вы присваиваете переменную объекта, поэтому выражение должно быть преобразовано в объект, поэтому я позабочусь, чтобы оно было». Скорее, C # говорит, что «это выражение должно иметь тип, и я должен иметь возможность сделать вывод, что тип совместим с объектом». Поскольку выражение не имеет типа, возникает ошибка.


Answer #2

И в Java, и в C # (и в большинстве других языков) результат выражения имеет тип. В случае троичного оператора существует два возможных подвыражения, вычисленных для результата, и оба должны иметь один и тот же тип. В случае Java переменная int может быть преобразована в Integer путем автобоксирования. Теперь, поскольку Integer и String наследуются от Object , их можно преобразовать в один и тот же тип простым сужающим преобразованием.

С другой стороны, в C # int является примитивом, и нет неявного преобразования в string или любой другой object .


Answer #3

Что касается генерической части:

two > six ? new List<int>() : new List<string>()

В C # компилятор пытается преобразовать правые части выражения в некоторый общий тип; поскольку List<int> и List<string> - это два разных сконструированных типа, один не может быть преобразован в другой.

В Java компилятор пытается найти общий супертип вместо преобразования, поэтому компиляция кода включает в себя неявное использование wildcards и стирание типов ;

two > six ? new ArrayList<Integer>() : new ArrayList<String>()

имеет тип компиляции ArrayList<?> (на самом деле, это также может быть ArrayList<? extends Serializable> или ArrayList<? extends Comparable<?>> , в зависимости от контекста использования, так как они оба являются общими универсальными супертипами) и тип времени выполнения raw ArrayList (так как это общий необработанный супертип).

Например (проверить это самостоятельно) ,

void test( List<?> list ) {
    System.out.println("foo");
}

void test( ArrayList<Integer> list ) { // note: can't use List<Integer> here
                                 // since both test() methods would clash after the erasure
    System.out.println("bar");
}

void test() {
    test( true ? new ArrayList<Object>() : new ArrayList<Object>() ); // foo
    test( true ? new ArrayList<Integer>() : new ArrayList<Object>() ); // foo 
    test( true ? new ArrayList<Integer>() : new ArrayList<Integer>() ); // bar
} // compiler automagically binds the correct generic QED

Answer #4

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

Пытаться:

Write(two > six ? two.ToString() : "6");




conditional-operator