Serious bugs with lifted/nullable conversions from int, allowing conversion from decimal

I’m just replying to the first part of the question to start with. (I suggest that the second part should be a separate question; it’s more likely to be a bug.)

There’s only an explicit conversion from decimal to int, but that conversion is being implicitly called in your code. The conversion happens in this IL:

IL_0010:  stloc.0
IL_0011:  ldloc.0
IL_0012:  call       int32 [mscorlib]System.Decimal::op_Explicit(valuetype [mscorlib]System.Decimal)
IL_0017:  call       valuetype NumberFixedPoint2 NumberFixedPoint2::op_Implicit(int32)

I believe this is the correct behaviour according to the spec, even though it’s surprising1. Let’s work our way through section 6.4.5 of the C# 4 spec (User-Defined Explicit Conversions). I’m not going to copy out all the text, as it would be tedious – just what the relevant results are in our case. Likewise I’m not going to use subscripts, as they don’t work well with code font here 🙂

  • Determine the types S0 and T0: S0 is decimal, and T0 is NumberFixedPoint2.
  • Find the set of types, D, from which used-defined conversion operators will be considered: just { decimal, NumberFixedPoint2 }
  • Find the set of applicable user-defined and lifted conversion operators, U. decimal encompasses int (section 6.4.3) because there’s a standard implicit conversion from int to decimal. So the explicit conversion operator is in U, and is indeed the only member of U
  • Find the most specific source type, Sx, of the operators in U
    • The operator doesn’t convert from S (decimal) so the first bullet is out
    • The operator doesn’t convert from a type that encompasses S (decimal encompasses int, not the other way round) so the second bullet is out
    • That just leaves the third bullet, which talks about the “most encompassing type” – well, we’ve only got one type, so that’s okay: Sx is int.
  • Find the most specific target type, Tx, of the operators in U
    • The operator convers straight to NumberFixedPoint2 so Tx is NumberFixedPoint2.
  • Find the most specific conversion operator:
    • U contains exactly one operator, which does indeed convert from Sx to Tx, so that’s the most specific operator
  • Finally, apply the conversion:
    • If S is not Sx, then a standard explicit conversion from S to Sx is performed. (So that’s decimal to int.)
    • The most specific user-defined conversion operator is invoked (your operator)
    • T is Tx so there’s no need for the conversion in the third bullet

The line in bold is the bit which confirms that a standard explicit conversion really is feasible, when only an explicit conversion from a different type is actually specified.


1 Well I found it surprising, at least. I’m not aware of seeing this before.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)