Reputation: 6293
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
Upvotes: 1
Views: 365
Reputation: 77606
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.
Upvotes: 4