I collect a few corner cases and brain teasers and would always like to hear more. The page only really covers C# language bits and bobs, but I also find core .NET things interesting too. For example, here's one which isn't on the page, but which I find incredible:
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));
I'd expect that to print False - after all, "new" (with a reference type) always creates a new object, doesn't it? The specs for both C# and the CLI indicate that it should. Well, not in this particular case. It prints True, and has done on every version of the framework I've tested it with. (I haven't tried it on Mono, admittedly...)
Just to be clear, this is only an example of the kind of thing I'm looking for - I wasn't particularly looking for discussion/explanation of this oddity. (It's not the same as normal string interning; in particular, string interning doesn't normally happen when a constructor is called.) I was really asking for similar odd behaviour.
Any other gems lurking out there?
They should have made 0 an integer even when there's an enum function overload.
I knew C# core team rationale for mapping 0 to enum, but still, it is not as orthogonal as it should be. Example from Npgsql.
Test example:
I found a second really strange corner case that beats my first one by a long shot.
String.Equals Method (String, String, StringComparison) is not actually side effect free.
I was working on a block of code that had this on a line by itself at the top of some function:
Removing that line lead to a stack overflow somewhere else in the program.
The code turned out to be installing a handler for what was in essence a BeforeAssemblyLoad event and trying to do
By now I shouldn't have to tell you. Using a culture that hasn't been used before in a string comparison causes an assembly load. InvariantCulture is not an exception to this.
Interesting - when I first looked at that I assumed it was something the C# compiler was checking for, but even if you emit the IL directly to remove any chance of interference it still happens, which means it really is the
newobj
op-code that's doing the checking.It also equates to
true
if you check againststring.Empty
which means this op-code must have special behaviour to intern empty strings.C# supports conversions between arrays and lists as long as the arrays are not multidimensional and there is an inheritance relation between the types and the types are reference types
Note that this does not work:
PropertyInfo.SetValue() can assign ints to enums, ints to nullable ints, enums to nullable enums, but not ints to nullable enums.
Full description here
Bankers' Rounding.
This one is not so much a compiler bug or malfunction, but certainly a strange corner case...
The .Net Framework employs a scheme or rounding known as Banker's Rounding.
In Bankers' Rounding the 0.5 numbers are rounded to the nearest even number, so
This can lead to some unexpected bugs in financial calculations based on the more well known Round-Half-Up rounding.
This is also true of Visual Basic.