Ambiguous implicit user defined conversion #2004
-
Hello Lets say I have the following code: internal static class Program
{
public static void Main(string[] args)
{
Val? s = null;
int? t = s;
}
public struct Val
{
public static implicit operator int(Val? val)
{
return 2;
}
}
} This code compiles because there is an implicit conversion between 'Val?' and 'int' and between 'int' and 'int?'. However when I add another implicit conversion: public static implicit operator int? (Val val)
{
return 3;
} the conversion becomes ambiguous which is odd because the first conversion is not lifted and will return '2' while the using the second operator will return 'null' because its a lifted conversion. Is this a bug or is this by design? |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
In both cases two conversions are used. What makes one better than the other? You're suggesting that lifted conversions should always be disfavored? |
Beta Was this translation helpful? Give feedback.
-
In the second case there is no conversion used (correct me if I am wrong). |
Beta Was this translation helpful? Give feedback.
-
Every value type instance can be a nullable instance but not every nullable instance can be a value type instance so in my opinion the first one should be preferred over the second. |
Beta Was this translation helpful? Give feedback.
-
First, looking at the relevant section of the spec, I think the rules mean that both the source and target types of the chosen operator have to be "most specific". There isn't any rule that would favor one over the other. So I think the error is correct. Second, that this code works at all is a deliberate spec violation. Conversion from |
Beta Was this translation helpful? Give feedback.
-
I have another problem with this conversion. internal static class Program
{
public static void Main(string[] args)
{
Val? s = null;
int? t = s; // Is 2
ParameterExpression parameter = Expression.Parameter(typeof(Val?));
Func<Val?, int?> convert = Expression.Lambda<Func<Val?, int?>>(Expression.Dynamic(Binder.Convert(CSharpBinderFlags.None, typeof(int?), typeof(Program)), typeof(int?), parameter), parameter).Compile();
t = convert(s); // Is null
}
public struct Val
{
public static implicit operator int(Val? val)
{
return 2;
}
}
} Why does the binder not reflect this spec violation? |
Beta Was this translation helpful? Give feedback.
First, looking at the relevant section of the spec, I think the rules mean that both the source and target types of the chosen operator have to be "most specific". There isn't any rule that would favor one over the other. So I think the error is correct.
Second, that this code works at all is a deliberate spec violation. Conversion from
S
toT
can be lifted to a conversion fromS?
toT?
, but there is no rule to lift a conversion where one of the types is already nullable. The compiler contains a lengthy comment that explains that it does this incorrect lifting to be compatible with the old (C# 5.0) compiler.