Even More Conversion Trivia
I learn something new about C# every day. This is a subtle and tricky language.
Pop quiz: foo is of a type which has a base class which has made a normal, everyday virtual override of System.Object.ToString. There are no additional overrides, hides, etc of ToString anywhere in foo's inheritance hierarchy. No ToString extension methods, etc. Under what circumstances do foo.ToString() and ((object)foo).ToString() produce different results? Remember, it is a virtual function, so the cast should not make a difference in what function is actually called.
As it turns out, my mistaken belief that the two of these have the same semantics caused a bug in the part of the compiler where we translate an expression tree lambda into a call to the Lambda<T> factory. That in turn was masking an even more subtle bug in the dynamic expression tree compiler.
Anyone out there have a guess as to what type and value of foo produces different behaviour here? I'll post the answer next time along with some discussion of the codegen issue.
Comments
Anonymous
April 30, 2007
The comment has been removedAnonymous
April 30, 2007
A hide does not qualify as an override does it? public class A { public override string ToString() { return "A"; } } public class B : A { public new string ToString() { return "B"; } }Anonymous
April 30, 2007
The comment has been removedAnonymous
April 30, 2007
Can one determine the pointer to value types (stack location) and reference types (heap location)? If so, boxing would change the pointer...Anonymous
April 30, 2007
ToString() does some reflection and prints the class name?Anonymous
April 30, 2007
There are no additional overrides or hides, sorry, I should have been more clear.Anonymous
April 30, 2007
Not sure this is what you mean, but it certainly exhibits the behavior you're descxribing: public interface IProblem { string ToString(); } public class MyBase { public override string ToString() { return "This is the Base class"; } } public class MyDerived : MyBase, IProblem { #region IProblem Members public string ToString() { return "Implementing this here interface"; } #endregion } class Program { static void Main(string[] args) { MyDerived foo = new MyDerived(); string s = foo.ToString(); Console.WriteLine(s); string s2 = ((object)foo).ToString(); Console.WriteLine(s2); } } Calling foo.ToString() calls the version defined in the IProblem interface. Casting to object clls the version defined in MyBase, because the interface does not override the ToString() method, but rather defines a new ToStrng() that is part of the MyDerived class, and part of the IProblem interface.Anonymous
April 30, 2007
ValueType overrides ToString(). ToString() on nullable types is lifted to the inner type. ToString() on a null value of a nullable type results in an empty string; but a cast to 'object' results in a null reference, this being a change implemented in the CLR released with VS2005 Beta 2. Calling a virtual method on a null reference (or indeed, any method with callvirt) results in a null reference exception. Example code: ---8<--- using System; enum Foo { Bar, Baz } class App { static void Main() { Foo? x = null; Catch(delegate { Console.WriteLine(x.ToString()); }); Catch(delegate { Console.WriteLine(((object) x).ToString()); }); } delegate void Code(); static void Catch(Code code) { try { Console.WriteLine("Executing..."); code(); Console.WriteLine("Done."); } catch (Exception ex) { Console.WriteLine("Caught: {0}: {1}", ex.GetType().Name, ex.Message); } } } --->8--- The code above uses an enum, but it can be rewritten with user-defined value type to eliminate all other overrides of ToString(), to stay within the original problem spec. The biggest clue was the conspicuous use of the word 'type' rather than 'class'.Anonymous
May 03, 2007
Which version of CLR you use? It seems that in .net 2.0 CLR this can't happen.Maybe you have reintroduced this in CLR 3.5?Anonymous
May 06, 2007
The biggest news in the C# community is the official announcement of Silverlight at the MIX conference.Anonymous
May 18, 2007
The comment has been removedAnonymous
May 18, 2007
Defining a custom conversion to a base class is definitely odd... and not allowed apparently, so my previous post doesn't hold water.Anonymous
August 28, 2007
You canh always redeclare a methods(also virtual ones) with the keyword new, making it "public new string ToString()"Anonymous
June 12, 2008
A puzzle in c# not related directly to the puzzle given here but thought it time to sent one the other way :-) If T is an enumeration would that statement always be true? Enum.IsDefined(typeof(T), default(T)) Well the answer is no, but when isn't it true? http://runefs.wordpress.com/2008/06/12/when-defaults-are-not-valid/