Оператор '??'нельзя применять к операндам типа для дочерних классов - PullRequest
4 голосов
/ 20 октября 2011

Следующий код выдает ошибку в заголовке во второй строке функции Main.

public class P {}

public class B : P {}

public class A : P {}

void Main()
{   
    P p = GetA()??GetB();
}

public A GetA() 
{
    return new A();
}

public B GetB()
{
    return new B();
}

Работает простая подстройка к строке, подобной этой

    p = (P)GetA()??GetB();
    or
    p = GetA()??(P)GetB();

.

Мне любопытно, почему компилятор не понимает, что оба являются дочерними классами левого контейнера и допускают операцию без приведения?

Ответы [ 3 ]

6 голосов
/ 20 октября 2011

Тип аргумента в левой части должен быть совместим с типом в правой части или наоборот. Другими словами, должно существовать неявное преобразование из B в A или из A в B.

var a = x ?? y;

В приведенном выше примере, если есть неявное преобразование из y в x, тогда тип x становится типом выражения. если нет неявного преобразования из y в x, но есть неявное преобразование из x в y, тогда тип y становится типом выражения. если нет конверсии ни в одном направлении, бум; ошибка компиляции. Из спецификации:

Тип выражения a ?? b зависит от того, какие неявные преобразования доступны между типами операндов. В порядке предпочтения, тип b - это A0, A или B, где A - это тип a, B - это тип b (при условии, что b имеет тип), а A0 - базовый тип A, если A - обнуляемый тип, или A в противном случае , В частности, b обрабатывается следующим образом:

• Если A не является обнуляемым типом или ссылочным типом, возникает ошибка времени компиляции.

• Если A является обнуляемым типом и существует неявное преобразование из b в A0, тип результата - A0. Во время выполнения a сначала оценивается. Если a не нуль, a разворачивается к типу A0, и это становится результатом. В противном случае b вычисляется и преобразуется в тип A0, и это становится результатом.

• В противном случае, если существует неявное преобразование из b в A, тип результата - A. Во время выполнения a сначала оценивается. Если a не нуль, a становится результатом. В противном случае b вычисляется и преобразуется в тип A. Это становится результатом.

• В противном случае, если b имеет тип B и существует неявное преобразование из A0 в B, тип результата - B. Во время выполнения a сначала оценивается a. Если a не является нулем, a разворачивается в тип A0 (если A и A0 не имеют одинаковый тип) и преобразуется в тип B, и это становится результатом. В противном случае b вычисляется и становится результатом.

• В противном случае a и b несовместимы, и возникает ошибка времени компиляции.

1 голос
/ 20 октября 2011

Мне любопытно, почему компилятор не понимает, что оба являются дочерними классами левого контейнера и допускают операцию без приведения?

Потому что тогда это будет разрешено:

public class SqlConnection : object {}    
public class Random : object {}

public SqlConnection GetA() { return new SqlConnection(); }
public Random GetB() { return new Random(); }

void Main()
{   
    var p = GetA() ?? GetB();
}
0 голосов
/ 20 октября 2011

операндов оператора ??должен быть того же типа:

    P a = GetA();
    P b = GetB();
    P p = a ?? b;
...