#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 приведении с одной стороны условия. Это элегантно решает проблему. СПАСИБО! 🙂