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?
This is one of the most unusual i've seen so far (aside from the ones here of course!):
It lets you declare it but has no real use, since it will always ask you to wrap whatever class you stuff in the center with another Turtle.
[joke] I guess it's turtles all the way down... [/joke]
When is a Boolean neither True nor False?
Bill discovered that you can hack a boolean so that if A is True and B is True, (A and B) is False.
Hacked Booleans
I think I showed you this one before, but I like the fun here - this took some debugging to track down! (the original code was obviously more complex and subtle...)
So what was T...
Answer: any
Nullable<T>
- such asint?
. All the methods are overridden, except GetType() which can't be; so it is cast (boxed) to object (and hence to null) to call object.GetType()... which calls on null ;-pUpdate: the plot thickens... Ayende Rahien threw down a similar challenge on his blog, but with a
where T : class, new()
:But it can be defeated! Using the same indirection used by things like remoting; warning - the following is pure evil:
With this in place, the
new()
call is redirected to the proxy (MyFunnyProxyAttribute
), which returnsnull
. Now go and wash your eyes!What if you have a generic class that has methods that could be made ambiguous depending on the type arguments? I ran into this situation recently writing a two-way dictionary. I wanted to write symmetric
Get()
methods that would return the opposite of whatever argument was passed. Something like this:All is well good if you make an instance where
T1
andT2
are different types:But if
T1
andT2
are the same (and probably if one was a subclass of another), it's a compiler error:Interestingly, all other methods in the second case are still usable; it's only calls to the now-ambiguous method that causes a compiler error. Interesting case, if a little unlikely and obscure.
In an API we're using, methods that return a domain object might return a special "null object". In the implementation of this, the comparison operator and the
Equals()
method are overridden to returntrue
if it is compared withnull
.So a user of this API might have some code like this:
or perhaps a bit more verbose, like this:
where
GetDefault()
is a method returning some default value that we want to use instead ofnull
. The surprise hit me when I was using ReSharper and following it's recommendation to rewrite either of this to the following:If the test object is a null object returned from the API instead of a proper
null
, the behavior of the code has now changed, as the null coalescing operator actually checks fornull
, not runningoperator=
orEquals()
.This one's pretty hard to top. I ran into it while I was trying to build a RealProxy implementation that truly supports Begin/EndInvoke (thanks MS for making this impossible to do without horrible hacks). This example is basically a bug in the CLR, the unmanaged code path for BeginInvoke doesn't validate that the return message from RealProxy.PrivateInvoke (and my Invoke override) is returning an instance of an IAsyncResult. Once it's returned, the CLR gets incredibly confused and loses any idea of whats going on, as demonstrated by the tests at the bottom.
Output: