C # Неявное преобразование распаковка условное выражение

#c# #wpf #implicit-conversion

#c# #wpf #неявное преобразование

Вопрос:

У меня есть конвертер String to Brush, который я использую в WPF для раскрашивания элементов списка на основе текстового содержимого.

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

Чтобы решить эту проблему, я создал класс OutputMessage, который я неявно использую как строку, но поскольку неявное преобразование создает новые экземпляры OutputMessage для каждой преобразуемой строки, теперь listbox сравнивает экземпляры, а не строковые значения, и ведет себя корректно.

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

Но я обнаружил странную ситуацию с распаковкой в конвертере:

  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            String txt = value is OutputMessage ? (OutputMessage)value : (String)value;
  

Делая это, вы получаете:

Ошибка 1 Тип условного выражения не может быть определен, поскольку ‘OutputMessage’ и ‘string’ неявно преобразуются друг в друга

Мы присваиваем значение строке, и в любом из случаев происходит неявное преобразование, поэтому я попытался использовать условное выражение, чтобы правильно выбрать «путь» для распаковки значения.

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

 String txt = (String)value;
  

или

 String txt = (OutputMessage)value;
  

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

В конечном итоге я решил проблему с помощью инструкций if и проверки типов, но это как бы убивает полезность неявного преобразования. Я надеялся, что условные выражения смогут справиться с этим: (

Комментарии:

1. Кстати, это не имеет ничего общего с распаковкой; это только для типов значений.

Ответ №1:

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

 String txt = value is OutputMessage ? (OutputMessage)value : (String)value;
  

Чтобы выполнить эту инструкцию, сначала вычисляется RHS присваивания, и в итоге получается выражение, которое может быть интерпретировано как имеющее тип OutputMessage или String . Это не учитывает то, что находится в LHS инструкции, поэтому это неоднозначно для компилятора. Помните, статический тип обеих частей условия должен быть одинаковым. Вы должны четко указать, какой тип вы хотите в этом случае, сделав обе части условного типа String или OutputMessage .

 String txt = value is OutputMessage ? (String)(OutputMessage)value : (String)value;
  

С другой стороны, я бы переписал это таким образом, чтобы вы тестировали тип OutputMessage (предполагая OutputMessage , что это ссылочный тип):

 var temp = value as OutputMessage;
String txt = temp != null ? (String)temp : (String)value;
  

Комментарии:

1. Я поставил лайк вам обоим, но поскольку Дэн ответил первым, я принял его ответ. Спасибо!

2. var temp = значение как OutputMessage; завершится ошибкой, если внутри него есть строка, распаковка не сработает :/

3. @Marino: Является OutputMessage типом значения? Если бы это было так, то это определенно не сработало бы. Обратите внимание, что упаковка применяется только к типам значений, в противном случае это считается приведением типов.

Ответ №2:

Вы можете сделать:

 String txt = value is OutputMessage ? (String)(OutputMessage)value : (String)value;
  

С другой стороны, вы можете изменить OutputMessage таким образом, чтобы одно из преобразований было явным, а не неявным (т. Е. разрешить неявное преобразование String в OutputMessage, но потребовать, чтобы OutputMessages явно преобразовывались в String.

Комментарии:

1. Вау, я никогда не думал о unbox приведении с одной стороны условия. Это элегантно решает проблему. СПАСИБО! 🙂