The operator '??' cannot be applied to type operands for child classes

The following code gives an error in the header in the second line in the main function.

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(); } 

Simple tuning to a line like these

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

work.

I am curious why the compiler does not understand that both are child classes of the left-side container and allow work without casting?

+4
source share
3 answers

The type of the argument on the left should be compatible with the type on the right, or vice versa. In other words, there must be an implicit conversion from B to A or from A to B

 var a = x ?? y; 

In the above case, if there is an implicit conversion from y to x , then the type x becomes the type of the expression. if there is no implicit conversion from y to x , but there is an implicit conversion from x to y , then the type y becomes the type of the expression. if the conversion does not exist in any direction, an arrow; collection error. From the specification:

Type of expression a? b depends on what implicit conversions are available between operand types. In order of preference, type ab is A0, A or B, where A is type a, B is type b (assuming b is of type), and A0 is the base type of A if A is a null type, or otherwise In particular, b is processed as follows:

• If A is not a null type or a reference type, a compile-time error occurs.

• If A is a null type and there is an implicit conversion from b to A0, then the result is A0. At runtime, a is first evaluated. If a is not null, a is expanded to enter A0, and this becomes the result. Otherwise, b is evaluated and converted to type A0, and this becomes the result.

• Otherwise, if there is an implicit conversion from b to A, the result is A. At run time, a is first evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and this becomes the result.

• Otherwise, if b is of type B and there is an implicit conversion from A0 to B, then the result is B. At run time, a is first evaluated. If a is not zero, a is expanded to enter A0 (unless A and A0 are the same type) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.

• Otherwise, a and b are incompatible, and a compile-time error occurs.

+6
source

I am curious why the compiler does not understand that both are child classes of the left-side container and allow work without casting?

Because then it will be allowed:

 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(); } 
+1
source

operator operands? must be of the same type:

  P a = GetA(); P b = GetB(); P p = a ?? b; 
-1
source

All Articles