Strangeness in C# compilation
May. 29th, 2007 11:48 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Something I spent a couple of hours digging into today, and caused much strangeness. If you use C# then knowing this might save you having to do the same...
When working out which method to call the compiler works its way up the calling chain from subclass to baseclass looking for a method signature that fits. It stops looking as soon as it finds one. The problem arises because the literal 0 can be mapped onto an enum without any casting. Which means that if there's a subclass with a method on it that takes an enumeration as a parameter and a baseclass with a method that takes an integer the call will be made to the subclass, producing an unexpected result. This is only true with a literal 0 - passing in a variable will work fine.
Sample Code
Fix
The following code works just fine:
Further Reading
For further info see the C# language specification, section 6.1.3
When working out which method to call the compiler works its way up the calling chain from subclass to baseclass looking for a method signature that fits. It stops looking as soon as it finds one. The problem arises because the literal 0 can be mapped onto an enum without any casting. Which means that if there's a subclass with a method on it that takes an enumeration as a parameter and a baseclass with a method that takes an integer the call will be made to the subclass, producing an unexpected result. This is only true with a literal 0 - passing in a variable will work fine.
Sample Code
public enum MyEnum { Zero, One, Two } class MyBaseClass { public string Something (int myInt) { return ("int" + myInt.ToString()); } } class MySubClass : MyBaseClass { public string Something(MyEnum myEnum) { return "enum" + ((int)myEnum).ToString(); } } public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { MySubClass x = new MySubClass(); MessageBox.Show(x.Something(1)); MessageBox.Show(x.Something(0)); } }This final bit of code will produce "int1" and "enum0".
Fix
The following code works just fine:
private void button1_Click(object sender, EventArgs e) { MySubClass x = new MySubClass(); int myCounter = 1; MessageBox.Show(x.Something(myCounter)); myCounter = 0; MessageBox.Show(x.Something(myCounter)); }
Further Reading
For further info see the C# language specification, section 6.1.3
C# Language Specification 6.1.3 Implicit enumeration conversions An implicit enumeration conversion permits the decimal-integer-literal 0 to be converted to any enum-type.
no subject
Date: 2007-05-30 06:50 am (UTC)((int)0)
should do the trick too, as the cast isn't directly an int lit and therefore shouldn't be converted.That's pretty nasty though. Why only 0? As far as enums are concerned, there really shouldn't be anything special about the value 0. Still, could be worse, could be C++...
no subject
Date: 2007-05-30 08:29 am (UTC)Personally, I'm generally against accessing lists via the array operator anyway, which is where I first detected this one. If the location matters then it should be stored in a named location, and if you need to iterate around the whole list then foreach should be used.
no subject
Date: 2007-05-30 12:29 pm (UTC)no subject
Date: 2007-05-30 01:04 pm (UTC)no subject
Date: 2007-05-30 02:27 pm (UTC)no subject
Date: 2007-05-30 03:13 pm (UTC)The language designers wanted to avoid
constructs like "(SomeEnum)0", because enums may be
[Flags]-able, and thus they may be "0" w/out having
a literal with the value "0".
Consider this:
if ((val & SomeEnum.Foo) == 0) {
}
W/out this rule, the bool expression has to
be written like:
if ((val & SomeEnum.Foo) == (SomeEnum)0) {
}
Personally, I'd rather they'd make people take the slightly more explicit route, as it would make both that code easier to read and my code more likely to run!
no subject
Date: 2007-05-31 08:15 am (UTC)no subject
Date: 2007-05-31 08:16 am (UTC)