Обновление!
См. Мое описание части спецификации C # ниже; Я думаю, что я что-то упускаю, потому что для me похоже, что поведение, которое я описываю в этом вопросе, на самом деле нарушает спецификацию.
Обновление 2!
Хорошо, после дальнейших размышлений и на основании некоторых комментариев, я думаю, что теперь я понимаю, что происходит. Слова «тип источника» в спецификации относятся к типу, который преобразуется из - т.е. Type2
в моем примере ниже - это просто означает, что компилятор может сузить кандидатов до определены два оператора (поскольку Type2
является типом источника для обоих). Однако это не может сузить выбор дальше. Таким образом, ключевые слова в спецификации (как это относится к этому вопросу) «тип источника» , который я ранее неверно истолковал (я думаю) как «объявление типа».
Оригинальный вопрос
Допустим, у меня определены следующие типы:
class Type0
{
public string Value { get; private set; }
public Type0(string value)
{
Value = value;
}
}
class Type1 : Type0
{
public Type1(string value) : base(value) { }
public static implicit operator Type1(Type2 other)
{
return new Type1("Converted using Type1's operator.");
}
}
class Type2 : Type0
{
public Type2(string value) : base(value) { }
public static implicit operator Type1(Type2 other)
{
return new Type1("Converted using Type2's operator.");
}
}
Тогда скажите, что я делаю это:
Type2 t2 = new Type2("B");
Type1 t1 = t2;
Очевидно, что это неоднозначно, так как не ясно, какой оператор implicit
следует использовать. У меня вопрос: поскольку я не вижу какого-либо способа разрешить эту неоднозначность (я не могу выполнить какое-то явное приведение, чтобы уточнить, какую версию я хочу), и все же приведенные выше определения классов компилируются - - с какой стати компилятор вообще разрешает эти implicit
операторы?
Вскрытие
Хорошо, я собираюсь пройтись по выдержке из спецификации C #, приведенной Гансом Пассантом, в попытке разобраться в этом.
Найдите множество типов D, из которых
пользовательские операторы преобразования будут
быть принятым во внимание. Этот набор состоит из S
(если S является классом или структурой), база
классы S (если S класс) и T
(если T является классом или структурой).
Мы конвертируем из Type2
( S ) в Type1
( T ). Таким образом, кажется, что здесь D будет включать в себя все три типа в примере: Type0
(потому что это базовый класс S ), Type1
( T *) 1064 *) и Type2
( S ).
Найдите набор применимых
определяемые пользователем операторы преобразования, U.
Этот набор состоит из пользовательских
объявлены операторы неявного преобразования
по классам или структурам в D, что
преобразовать из типа, охватывающего S в
тип, охватываемый T. Если U
пусто, преобразование не определено и
происходит ошибка времени компиляции.
Хорошо, у нас есть два оператора, удовлетворяющих этим условиям. Версия, объявленная в Type1
, отвечает требованиям, поскольку Type1
находится в D и преобразуется из Type2
(что, очевидно, охватывает S ) в Type1
(что, очевидно, охватывается T ). Версия в Type2
также соответствует требованиям по тем же причинам. Так что U включает в себя оба этих оператора.
Наконец, в отношении поиска наиболее конкретного «типа источника» SX операторов в U :
Если какой-либо из операторов в U преобразуется из S, то SX равен S.
Теперь оба оператора в U конвертируют из S - так что это говорит мне, что SX равно S .
Не означает ли это, что следует использовать версию Type2
?
Но подождите! Я в замешательстве!
Не могу ли я только определить версию Type1
оператора, в этом случае единственным оставшимся кандидатом будет версия Type1
, и все же в соответствии со спецификацией SX будет Type2
? Это выглядит как возможный сценарий, в котором спецификация требует чего-то невозможного (а именно, что преобразование, объявленное в Type2
, должно использоваться, когда на самом деле оно не существует).