简体   繁体   中英

Why there is no conversion when casting nullable type to it's base class in Roslyn?

Lets take the following code:

int? a = null;
int b = (int)a;

And extract CastExpressionSyntax for (int)a expression.

There is no conversion:

semanticModel.GetConversion(node) == {Identity}

There is no symbol (I hoped for Nullable<T> implicit operator T )

semanticModel.GetSymbolInfo(node).Method == null

Type info's both values are same

semanticModel.GetTypeInfo(node) == {Type = Int32, ConvertedType = Int32}
semanticModel.GetTypeInfo(node.Expression) == {Type = Int32?, ConvertedType = Int32?}

Is there a correct way to detect nullable to non nullable cast, or i need to manually look if one of type infos is nullable and other is not?

Example of a different behavior:

Lets take structure:

 public struct N<T> where T : struct
 {
     public static explicit operator T(N<T> value)
     {
        return default(T);
     }
 }

And use it like nullable before

 N<int> e;
 int d = (int) e;

@Kirk Woll is right that GetConversion and GetTypeInfo would be the same, but GetSymbolInfo would return public static explicit operator T(N<T> value) method.

Nullable has exactly the same method, but it's not returned.

There is no call to operator emmited compiller generates direct call to Value property.

IL_0001:  ldloca.s    00 // a
IL_0003:  initobj     System.Nullable<System.Int32>
IL_0009:  ldloca.s    00 // a
IL_000B:  call        System.Nullable<System.Int32>.get_Value
IL_0010:  stloc.1     // b

In a cast operation:

int b = (int)a;

You have the cast expression:

(int)a

The CastExpressionSyntax has an Expression property (representing a ) and the Type property (representing int ). Thus in my implementation of this using VisitCastExpression , I query both values to determine the from and the to of the cast:

var typeInfo = model.GetTypeInfo(node.Expression);
var originalType = typeInfo.Type;
var convertedType = typeInfo.ConvertedType;
var destinationType = model.GetTypeInfo(node.Type).Type;

destinationType is always what you are casting to (in your case int ). originalType is the type of the expression before it has undergone any implicit conversions. And convertedType is the type of the expression after it has undergone any implicit conversions. In your example, the convertedType and the originalType should both be int? .

So I'm not entirely sure in what way you were hoping Roslyn would behave differently, but it seems to me to be behaving exactly as I'd expect.

As far as why the symbol information is not being returned, my guess is that the compiler doesn't actually emit code that invokes that operator overload and handles such conversions implicitly. Thus it would have been incorrect if it provided that symbol.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM