[c#] What's the strangest corner case you've seen in C# or .NET?

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 question is related to c# .net

The answer is


PropertyInfo.SetValue() can assign ints to enums, ints to nullable ints, enums to nullable enums, but not ints to nullable enums.

enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!

Full description here


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.

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

It also equates to true if you check against string.Empty which means this op-code must have special behaviour to intern empty strings.


From a question I asked not long ago:

Conditional operator cannot cast implicitly?

Given:

Bool aBoolValue;

Where aBoolValue is assigned either True or False;

The following will not compile:

Byte aByteValue = aBoolValue ? 1 : 0;

But this would:

Int anIntValue = aBoolValue ? 1 : 0;

The answer provided is pretty good too.


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


This one is pretty straightforward but I still find it somewhat interesting. What would be the value of x after the call to Foo?

static int x = 0;

public static void Foo()
{
    try { return; }
    finally { x = 1; }
}

static void Main() { Foo(); }

Have you ever thought the C# compiler could generate invalid CIL? Run this and you'll get a TypeLoadException:

interface I<T> {
  T M(T p);
}
abstract class A<T> : I<T> {
  public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
  public override T M(T p) { return p; }
  public int M(int p) { return p * 2; }
}
class C : B<int> { }

class Program {
  static void Main(string[] args) {
    Console.WriteLine(new C().M(42));
  }
}

I don't know how it fares in the C# 4.0 compiler though.

EDIT: this is the output from my system:

C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

  interface I<T> {
    T M(T p);
  }
  abstract class A<T> : I<T> {
    public abstract T M(T p);
  }
  abstract class B<T> : A<T>, I<int> {
    public override T M(T p) { return p; }
    public int M(int p) { return p * 2; }
  }
  class C : B<int> { }

  class Program {
    static void Main(string[] args) {
      Console.WriteLine(new C().M(11));
    }
  }

}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Temp>Program

Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
   at ConsoleApplication1.Program.Main(String[] args)

C:\Temp>peverify Program.exe

Microsoft (R) .NET Framework PE Verifier.  Version  3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[token  0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe

C:\Temp>ver

Microsoft Windows XP [Version 5.1.2600]

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


VB.NET, nullables and the ternary operator:

Dim i As Integer? = If(True, Nothing, 5)

This took me some time to debug, since I expected i to contain Nothing.

What does i really contain? 0.

This is surprising but actually "correct" behavior: Nothing in VB.NET is not exactly the same as null in CLR: Nothing can either mean null or default(T) for a value type T, depending on the context. In the above case, If infers Integer as the common type of Nothing and 5, so, in this case, Nothing means 0.


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

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

Note that this does not work:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

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:

class TwoWayRelationship<T1, T2>
{
    public T2 Get(T1 key) { /* ... */ }
    public T1 Get(T2 key) { /* ... */ }
}

All is well good if you make an instance where T1 and T2 are different types:

var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");

But if T1 and T2 are the same (and probably if one was a subclass of another), it's a compiler error:

var r2 = new TwoWayRelationship<int, int>();
r2.Get(1);  // "The call is ambiguous..."

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.


Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

The output is "Attempted to read protected memory. This is an indication that other memory is corrupt."


I think the answer to the question is because .net uses string interning something that might cause equal strings to point to the same object (since a strings are mutable this is not a problem)

(I'm not talking about the overridden equality operator on the string class)


If you have the extension method:

public static bool? ToBoolean(this string s)
{
    bool result;

    if (bool.TryParse(s, out result))
        return result;
    else
        return null;
}

and this code:

string nullStr = null;
var res = nullStr.ToBoolean();

This will not throw an exception because it is an extension method (and really HelperClass.ToBoolean(null)) and not an instance method. This can be confusing.


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

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

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.


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

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

Note that this does not work:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

Here's one I only found out about recently...

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

The above looks crazy at first glance, but is actually legal.No, really (although I've missed out a key part, but it isn't anything hacky like "add a class called IFoo" or "add a using alias to point IFoo at a class").

See if you can figure out why, then: Who says you can’t instantiate an interface?


This one had me truly puzzled (I apologise for the length but it's WinForm). I posted it in the newsgroups a while back.

I've come across an interesting bug. I have workarounds but i'd like to know the root of the problem. I've stripped it down into a short file and hope someone might have an idea about what's going on.

It's a simple program that loads a control onto a form and binds "Foo" against a combobox ("SelectedItem") for it's "Bar" property and a datetimepicker ("Value") for it's "DateTime" property. The DateTimePicker.Visible value is set to false. Once it's loaded up, select the combobox and then attempt to deselect it by selecting the checkbox. This is rendered impossible by the combobox retaining the focus, you cannot even close the form, such is it's grasp on the focus.

I have found three ways of fixing this problem.

a) Remove the binding to Bar (a bit obvious)

b) Remove the binding to DateTime

c) Make the DateTimePicker visible !?!

I'm currently running Win2k. And .NET 2.00, I think 1.1 has the same problem. Code is below.

using System;
using System.Collections;
using System.Windows.Forms;

namespace WindowsApplication6
{
    public class Bar
    {
        public Bar()
        {
        }
    }

    public class Foo
    {
        private Bar m_Bar = new Bar();
        private DateTime m_DateTime = DateTime.Now;

        public Foo()
        {
        }

        public Bar Bar
        {
            get
            {
                return m_Bar;
            }
            set
            {
                m_Bar = value;
            }
        }

        public DateTime DateTime
        {
            get
            {
                return m_DateTime;
            }
            set
            {
                m_DateTime = value;
            }
        }
    }

    public class TestBugControl : UserControl
    {
        public TestBugControl()
        {
            InitializeComponent();
        }

        public void InitializeData(IList types)
        {
            this.cBoxType.DataSource = types;
        }

        public void BindFoo(Foo foo)
        {
            this.cBoxType.DataBindings.Add("SelectedItem", foo, "Bar");
            this.dtStart.DataBindings.Add("Value", foo, "DateTime");
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.cBoxType = new System.Windows.Forms.ComboBox();
            this.dtStart = new System.Windows.Forms.DateTimePicker();
            this.SuspendLayout();
            //
            // checkBox1
            //
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(14, 5);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(97, 20);
            this.checkBox1.TabIndex = 0;
            this.checkBox1.Text = "checkBox1";
            this.checkBox1.UseVisualStyleBackColor = true;
            //
            // cBoxType
            //
            this.cBoxType.FormattingEnabled = true;
            this.cBoxType.Location = new System.Drawing.Point(117, 3);
            this.cBoxType.Name = "cBoxType";
            this.cBoxType.Size = new System.Drawing.Size(165, 24);
            this.cBoxType.TabIndex = 1;
            //
            // dtStart
            //
            this.dtStart.Location = new System.Drawing.Point(117, 40);
            this.dtStart.Name = "dtStart";
            this.dtStart.Size = new System.Drawing.Size(165, 23);
            this.dtStart.TabIndex = 2;
            this.dtStart.Visible = false;
            //
            // TestBugControl
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.dtStart);
            this.Controls.Add(this.cBoxType);
            this.Controls.Add(this.checkBox1);
            this.Font = new System.Drawing.Font("Verdana", 9.75F,
            System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
            ((byte)(0)));
            this.Margin = new System.Windows.Forms.Padding(4);
            this.Name = "TestBugControl";
            this.Size = new System.Drawing.Size(285, 66);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox checkBox1;
        private System.Windows.Forms.ComboBox cBoxType;
        private System.Windows.Forms.DateTimePicker dtStart;
    }

    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            InitializeControl();
        }

        public void InitializeControl()
        {
            TestBugControl control = new TestBugControl();
            IList list = new ArrayList();
            for (int i = 0; i < 10; i++)
            {
                list.Add(new Bar());
            }
            control.InitializeData(list);
            control.BindFoo(new Foo());
            this.Controls.Add(control);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }

        #endregion
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

The following doesn't work:

if (something)
    doit();
else
    var v = 1 + 2;

But this works:

if (something)
    doit();
else {
    var v = 1 + 2;
}

I'm arriving a bit late to the party, but I've got three four five:

  1. If you poll InvokeRequired on a control that hasn't been loaded/shown, it will say false - and blow up in your face if you try to change it from another thread (the solution is to reference this.Handle in the creator of the control).

  2. Another one which tripped me up is that given an assembly with:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    if you calculate MyEnum.Red.ToString() in another assembly, and in between times someone has recompiled your enum to:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    at runtime, you will get "Black".

  3. I had a shared assembly with some handy constants in. My predecessor had left a load of ugly-looking get-only properties, I thought I'd get rid of the clutter and just use public const. I was more than a little surprised when VS compiled them to their values, and not references.

  4. If you implement a new method of an interface from another assembly, but you rebuild referencing the old version of that assembly, you get a TypeLoadException (no implementation of 'NewMethod'), even though you have implemented it (see here).

  5. Dictionary<,>: "The order in which the items are returned is undefined". This is horrible, because it can bite you sometimes, but work others, and if you've just blindly assumed that Dictionary is going to play nice ("why shouldn't it? I thought, List does"), you really have to have your nose in it before you finally start to question your assumption.


Have you ever thought the C# compiler could generate invalid CIL? Run this and you'll get a TypeLoadException:

interface I<T> {
  T M(T p);
}
abstract class A<T> : I<T> {
  public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
  public override T M(T p) { return p; }
  public int M(int p) { return p * 2; }
}
class C : B<int> { }

class Program {
  static void Main(string[] args) {
    Console.WriteLine(new C().M(42));
  }
}

I don't know how it fares in the C# 4.0 compiler though.

EDIT: this is the output from my system:

C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

  interface I<T> {
    T M(T p);
  }
  abstract class A<T> : I<T> {
    public abstract T M(T p);
  }
  abstract class B<T> : A<T>, I<int> {
    public override T M(T p) { return p; }
    public int M(int p) { return p * 2; }
  }
  class C : B<int> { }

  class Program {
    static void Main(string[] args) {
      Console.WriteLine(new C().M(11));
    }
  }

}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Temp>Program

Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
   at ConsoleApplication1.Program.Main(String[] args)

C:\Temp>peverify Program.exe

Microsoft (R) .NET Framework PE Verifier.  Version  3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[token  0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe

C:\Temp>ver

Microsoft Windows XP [Version 5.1.2600]

I think the answer to the question is because .net uses string interning something that might cause equal strings to point to the same object (since a strings are mutable this is not a problem)

(I'm not talking about the overridden equality operator on the string class)


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:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

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

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

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.


Consider this weird case:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

If Base and Derived are declared in the same assembly, the compiler will make Base::Method virtual and sealed (in the CIL), even though Base doesn't implement the interface.

If Base and Derived are in different assemblies, when compiling the Derived assembly, the compiler won't change the other assembly, so it will introduce a member in Derived that will be an explicit implementation for MyInterface::Method that will just delegate the call to Base::Method.

The compiler has to do this in order to support polymorphic dispatch with regards to the interface, i.e. it has to make that method virtual.


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.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using System.Runtime.Remoting.Messaging;

namespace BrokenProxy
{
    class NotAnIAsyncResult
    {
        public string SomeProperty { get; set; }
    }

    class BrokenProxy : RealProxy
    {
        private void HackFlags()
        {
            var flagsField = typeof(RealProxy).GetField("_flags", BindingFlags.NonPublic | BindingFlags.Instance);
            int val = (int)flagsField.GetValue(this);
            val |= 1; // 1 = RemotingProxy, check out System.Runtime.Remoting.Proxies.RealProxyFlags
            flagsField.SetValue(this, val);
        }

        public BrokenProxy(Type t)
            : base(t)
        {
            HackFlags();
        }

        public override IMessage Invoke(IMessage msg)
        {
            var naiar = new NotAnIAsyncResult();
            naiar.SomeProperty = "o noes";
            return new ReturnMessage(naiar, null, 0, null, (IMethodCallMessage)msg);
        }
    }

    interface IRandomInterface
    {
        int DoSomething();
    }

    class Program
    {
        static void Main(string[] args)
        {
            BrokenProxy bp = new BrokenProxy(typeof(IRandomInterface));
            var instance = (IRandomInterface)bp.GetTransparentProxy();
            Func<int> doSomethingDelegate = instance.DoSomething;
            IAsyncResult notAnIAsyncResult = doSomethingDelegate.BeginInvoke(null, null);

            var interfaces = notAnIAsyncResult.GetType().GetInterfaces();
            Console.WriteLine(!interfaces.Any() ? "No interfaces on notAnIAsyncResult" : "Interfaces");
            Console.WriteLine(notAnIAsyncResult is IAsyncResult); // Should be false, is it?!
            Console.WriteLine(((NotAnIAsyncResult)notAnIAsyncResult).SomeProperty);
            Console.WriteLine(((IAsyncResult)notAnIAsyncResult).IsCompleted); // No way this works.
        }
    }
}

Output:

No interfaces on notAnIAsyncResult
True
o noes

Unhandled Exception: System.EntryPointNotFoundException: Entry point was not found.
   at System.IAsyncResult.get_IsCompleted()
   at BrokenProxy.Program.Main(String[] args) 

This one had me truly puzzled (I apologise for the length but it's WinForm). I posted it in the newsgroups a while back.

I've come across an interesting bug. I have workarounds but i'd like to know the root of the problem. I've stripped it down into a short file and hope someone might have an idea about what's going on.

It's a simple program that loads a control onto a form and binds "Foo" against a combobox ("SelectedItem") for it's "Bar" property and a datetimepicker ("Value") for it's "DateTime" property. The DateTimePicker.Visible value is set to false. Once it's loaded up, select the combobox and then attempt to deselect it by selecting the checkbox. This is rendered impossible by the combobox retaining the focus, you cannot even close the form, such is it's grasp on the focus.

I have found three ways of fixing this problem.

a) Remove the binding to Bar (a bit obvious)

b) Remove the binding to DateTime

c) Make the DateTimePicker visible !?!

I'm currently running Win2k. And .NET 2.00, I think 1.1 has the same problem. Code is below.

using System;
using System.Collections;
using System.Windows.Forms;

namespace WindowsApplication6
{
    public class Bar
    {
        public Bar()
        {
        }
    }

    public class Foo
    {
        private Bar m_Bar = new Bar();
        private DateTime m_DateTime = DateTime.Now;

        public Foo()
        {
        }

        public Bar Bar
        {
            get
            {
                return m_Bar;
            }
            set
            {
                m_Bar = value;
            }
        }

        public DateTime DateTime
        {
            get
            {
                return m_DateTime;
            }
            set
            {
                m_DateTime = value;
            }
        }
    }

    public class TestBugControl : UserControl
    {
        public TestBugControl()
        {
            InitializeComponent();
        }

        public void InitializeData(IList types)
        {
            this.cBoxType.DataSource = types;
        }

        public void BindFoo(Foo foo)
        {
            this.cBoxType.DataBindings.Add("SelectedItem", foo, "Bar");
            this.dtStart.DataBindings.Add("Value", foo, "DateTime");
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.cBoxType = new System.Windows.Forms.ComboBox();
            this.dtStart = new System.Windows.Forms.DateTimePicker();
            this.SuspendLayout();
            //
            // checkBox1
            //
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(14, 5);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(97, 20);
            this.checkBox1.TabIndex = 0;
            this.checkBox1.Text = "checkBox1";
            this.checkBox1.UseVisualStyleBackColor = true;
            //
            // cBoxType
            //
            this.cBoxType.FormattingEnabled = true;
            this.cBoxType.Location = new System.Drawing.Point(117, 3);
            this.cBoxType.Name = "cBoxType";
            this.cBoxType.Size = new System.Drawing.Size(165, 24);
            this.cBoxType.TabIndex = 1;
            //
            // dtStart
            //
            this.dtStart.Location = new System.Drawing.Point(117, 40);
            this.dtStart.Name = "dtStart";
            this.dtStart.Size = new System.Drawing.Size(165, 23);
            this.dtStart.TabIndex = 2;
            this.dtStart.Visible = false;
            //
            // TestBugControl
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.dtStart);
            this.Controls.Add(this.cBoxType);
            this.Controls.Add(this.checkBox1);
            this.Font = new System.Drawing.Font("Verdana", 9.75F,
            System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
            ((byte)(0)));
            this.Margin = new System.Windows.Forms.Padding(4);
            this.Name = "TestBugControl";
            this.Size = new System.Drawing.Size(285, 66);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox checkBox1;
        private System.Windows.Forms.ComboBox cBoxType;
        private System.Windows.Forms.DateTimePicker dtStart;
    }

    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            InitializeControl();
        }

        public void InitializeControl()
        {
            TestBugControl control = new TestBugControl();
            IList list = new ArrayList();
            for (int i = 0; i < 10; i++)
            {
                list.Add(new Bar());
            }
            control.InitializeData(list);
            control.BindFoo(new Foo());
            this.Controls.Add(control);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }

        #endregion
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

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 return true if it is compared with null.

So a user of this API might have some code like this:

return test != null ? test : GetDefault();

or perhaps a bit more verbose, like this:

if (test == null)
    return GetDefault();
return test;

where GetDefault() is a method returning some default value that we want to use instead of null. The surprise hit me when I was using ReSharper and following it's recommendation to rewrite either of this to the following:

return test ?? GetDefault();

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 for null, not running operator= or Equals().


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:

class TwoWayRelationship<T1, T2>
{
    public T2 Get(T1 key) { /* ... */ }
    public T1 Get(T2 key) { /* ... */ }
}

All is well good if you make an instance where T1 and T2 are different types:

var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");

But if T1 and T2 are the same (and probably if one was a subclass of another), it's a compiler error:

var r2 = new TwoWayRelationship<int, int>();
r2.Get(1);  // "The call is ambiguous..."

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.


I'm arriving a bit late to the party, but I've got three four five:

  1. If you poll InvokeRequired on a control that hasn't been loaded/shown, it will say false - and blow up in your face if you try to change it from another thread (the solution is to reference this.Handle in the creator of the control).

  2. Another one which tripped me up is that given an assembly with:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    if you calculate MyEnum.Red.ToString() in another assembly, and in between times someone has recompiled your enum to:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    at runtime, you will get "Black".

  3. I had a shared assembly with some handy constants in. My predecessor had left a load of ugly-looking get-only properties, I thought I'd get rid of the clutter and just use public const. I was more than a little surprised when VS compiled them to their values, and not references.

  4. If you implement a new method of an interface from another assembly, but you rebuild referencing the old version of that assembly, you get a TypeLoadException (no implementation of 'NewMethod'), even though you have implemented it (see here).

  5. Dictionary<,>: "The order in which the items are returned is undefined". This is horrible, because it can bite you sometimes, but work others, and if you've just blindly assumed that Dictionary is going to play nice ("why shouldn't it? I thought, List does"), you really have to have your nose in it before you finally start to question your assumption.


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:

namespace Craft
{
    enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };


   class Mate
    {
        static void Main(string[] args)
        {

            JustTest(Symbol.Alpha); // enum
            JustTest(0); // why enum
            JustTest((int)0); // why still enum

            int i = 0;

            JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version

            JustTest(i); // it's ok from down here and below
            JustTest(1);
            JustTest("string");
            JustTest(Guid.NewGuid());
            JustTest(new DataTable());

            Console.ReadLine();
        }

        static void JustTest(Symbol a)
        {
            Console.WriteLine("Enum");
        }

        static void JustTest(object o)
        {
            Console.WriteLine("Object");
        }
    }
}

The following prints False instead of throwing an overflow exception:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}

Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

The output is "Attempted to read protected memory. This is an indication that other memory is corrupt."


I'm not sure if you'd say this is a Windows Vista/7 oddity or a .Net oddity but it had me scratching my head for a while.

string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."

In Windows Vista/7 the file will actually be written to C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt


There is something really exciting about C#, the way it handles closures.

Instead of copying the stack variable values to the closure free variable, it does that preprocessor magic wrapping all occurences of the variable into an object and thus moves it out of stack - straight to the heap! :)

I guess, that makes C# even more functionally-complete (or lambda-complete huh)) language than ML itself (which uses stack value copying AFAIK). F# has that feature too, as C# does.

That does bring much delight to me, thank you MS guys!

It's not an oddity or corner case though... but something really unexpected from a stack-based VM language :)


here are a few of mine:

  1. this can be null when calling an instance method with out a NullReferenceException being thrown
  2. a default enumeration value doesn't have to be defined for the enumeration

Simple one first: enum NoZero { Number = 1 }

        public bool ReturnsFalse()
        {
            //The default value is not defined!
            return Enum.IsDefined(typeof (NoZero), default(NoZero));
        }

The below code can actually print true!

 internal sealed class Strange
{
    public void Foo()
    {
        Console.WriteLine(this == null);
    }
}

A simple piece of client code that will result in that is delegate void HelloDelegate(Strange bar);

public class Program
{
    [STAThread()]
    public static void Main(string[] args)
    {
        Strange bar = null;
        var hello = new DynamicMethod("ThisIsNull",
            typeof(void), new[] { typeof(Strange) },
         typeof(Strange).Module);
        ILGenerator il = hello.GetILGenerator(256);
        il.Emit(OpCodes.Ldarg_0);
        var foo = typeof(Strange).GetMethod("Foo");
        il.Emit(OpCodes.Call, foo);
        il.Emit(OpCodes.Ret);
        var print = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate));
        print(bar);
        Console.ReadLine();
    }
}

this is actually true in most languages as long as the instance method when called doesn't use the state of the object. this is only dereferenced when the state of the object is accessed


If you have the extension method:

public static bool? ToBoolean(this string s)
{
    bool result;

    if (bool.TryParse(s, out result))
        return result;
    else
        return null;
}

and this code:

string nullStr = null;
var res = nullStr.ToBoolean();

This will not throw an exception because it is an extension method (and really HelperClass.ToBoolean(null)) and not an instance method. This can be confusing.


here are a few of mine:

  1. this can be null when calling an instance method with out a NullReferenceException being thrown
  2. a default enumeration value doesn't have to be defined for the enumeration

Simple one first: enum NoZero { Number = 1 }

        public bool ReturnsFalse()
        {
            //The default value is not defined!
            return Enum.IsDefined(typeof (NoZero), default(NoZero));
        }

The below code can actually print true!

 internal sealed class Strange
{
    public void Foo()
    {
        Console.WriteLine(this == null);
    }
}

A simple piece of client code that will result in that is delegate void HelloDelegate(Strange bar);

public class Program
{
    [STAThread()]
    public static void Main(string[] args)
    {
        Strange bar = null;
        var hello = new DynamicMethod("ThisIsNull",
            typeof(void), new[] { typeof(Strange) },
         typeof(Strange).Module);
        ILGenerator il = hello.GetILGenerator(256);
        il.Emit(OpCodes.Ldarg_0);
        var foo = typeof(Strange).GetMethod("Foo");
        il.Emit(OpCodes.Call, foo);
        il.Emit(OpCodes.Ret);
        var print = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate));
        print(bar);
        Console.ReadLine();
    }
}

this is actually true in most languages as long as the instance method when called doesn't use the state of the object. this is only dereferenced when the state of the object is accessed


Assign This!


This is one that I like to ask at parties (which is probably why I don't get invited anymore):

Can you make the following piece of code compile?

    public void Foo()
    {
        this = new Teaser();
    }

An easy cheat could be:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

But the real solution is this:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

So it's a little know fact that value types (structs) can reassign their this variable.


The following prints False instead of throwing an overflow exception:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}

C# Accessibility Puzzler


The following derived class is accessing a private field from its base class, and the compiler silently looks to the other side:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

The field is indeed private:

private int m_basePrivateField = 0;

Care to guess how we can make such code compile?

.

.

.

.

.

.

.

Answer


The trick is to declare Derived as an inner class of Base:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

Inner classes are given full access to the outer class members. In this case the inner class also happens to derive from the outer class. This allows us to "break" the encapsulation of private members.


There is something really exciting about C#, the way it handles closures.

Instead of copying the stack variable values to the closure free variable, it does that preprocessor magic wrapping all occurences of the variable into an object and thus moves it out of stack - straight to the heap! :)

I guess, that makes C# even more functionally-complete (or lambda-complete huh)) language than ML itself (which uses stack value copying AFAIK). F# has that feature too, as C# does.

That does bring much delight to me, thank you MS guys!

It's not an oddity or corner case though... but something really unexpected from a stack-based VM language :)


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.

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

It also equates to true if you check against string.Empty which means this op-code must have special behaviour to intern empty strings.


C# Accessibility Puzzler


The following derived class is accessing a private field from its base class, and the compiler silently looks to the other side:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

The field is indeed private:

private int m_basePrivateField = 0;

Care to guess how we can make such code compile?

.

.

.

.

.

.

.

Answer


The trick is to declare Derived as an inner class of Base:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

Inner classes are given full access to the outer class members. In this case the inner class also happens to derive from the outer class. This allows us to "break" the encapsulation of private members.


This is the strangest I've encountered by accident:

public class DummyObject
{
    public override string ToString()
    {
        return null;
    }
}

Used as follows:

DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);

Will throw a NullReferenceException. Turns out the multiple additions are compiled by the C# compiler to a call to String.Concat(object[]). Prior to .NET 4, there is a bug in just that overload of Concat where the object is checked for null, but not the result of ToString():

object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;

This is a bug by ECMA-334 §14.7.4:

The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string operand is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.


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

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

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.


This is one of the most unusual i've seen so far (aside from the ones here of course!):

public class Turtle<T> where T : Turtle<T>
{
}

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]


Here is an example of how you can create a struct that causes the error message "Attempted to read or write protected memory. This is often an indication that other memory is corrupt". The difference between success and failure is very subtle.

The following unit test demonstrates the problem.

See if you can work out what went wrong.

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

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


Few years ago, when working on loyality program, we had an issue with the amount of points given to customers. The issue was related to casting/converting double to int.

In code below:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

does i1 == i2 ?

It turns out that i1 != i2. Because of different rounding policies in Convert and cast operator the actual values are:

i1 == 14
i2 == 13

It's always better to call Math.Ceiling() or Math.Floor() (or Math.Round with MidpointRounding that meets our requirements)

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

The following doesn't work:

if (something)
    doit();
else
    var v = 1 + 2;

But this works:

if (something)
    doit();
else {
    var v = 1 + 2;
}

The scoping in c# is truly bizarre at times. Lets me give you one example:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

This fails to compile, because command is redeclared? There are some interested guesswork as to why it works that way in this thread on stackoverflow and in my blog.


I think the answer to the question is because .net uses string interning something that might cause equal strings to point to the same object (since a strings are mutable this is not a problem)

(I'm not talking about the overridden equality operator on the string class)


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

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

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.


Few years ago, when working on loyality program, we had an issue with the amount of points given to customers. The issue was related to casting/converting double to int.

In code below:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

does i1 == i2 ?

It turns out that i1 != i2. Because of different rounding policies in Convert and cast operator the actual values are:

i1 == 14
i2 == 13

It's always better to call Math.Ceiling() or Math.Floor() (or Math.Round with MidpointRounding that meets our requirements)

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

I think the answer to the question is because .net uses string interning something that might cause equal strings to point to the same object (since a strings are mutable this is not a problem)

(I'm not talking about the overridden equality operator on the string class)


The following might be general knowledge I was just simply lacking, but eh. Some time ago, we had a bug case which included virtual properties. Abstracting the context a bit, consider the following code, and apply breakpoint to specified area :

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        d.Property = "AWESOME";
    }
}

class Base
{
    string _baseProp;
    public virtual string Property 
    { 
        get 
        {
            return "BASE_" + _baseProp;
        }
        set
        {
            _baseProp = value;
            //do work with the base property which might 
            //not be exposed to derived types
            //here
            Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
        }
    }
}

class Derived : Base
{
    string _prop;
    public override string Property 
    {
        get { return _prop; }
        set 
        { 
            _prop = value; 
            base.Property = value;
        } //<- put a breakpoint here then mouse over BaseProperty, 
          //   and then mouse over the base.Property call inside it.
    }

    public string BaseProperty { get { return base.Property; } private set { } }
}

While in the Derived object context, you can get the same behavior when adding base.Property as a watch, or typing base.Property into the quickwatch.

Took me some time to realize what was going on. In the end I was enlightened by the Quickwatch. When going into the Quickwatch and exploring the Derived object d (or from the object's context, this) and selecting the field base, the edit field on top of the Quickwatch displays the following cast:

((TestProject1.Base)(d))

Which means that if base is replaced as such, the call would be

public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }

for the Watches, Quickwatch and the debugging mouse-over tooltips, and it would then make sense for it to display "AWESOME" instead of "BASE_AWESOME" when considering polymorphism. I'm still unsure why it would transform it into a cast, one hypothesis is that call might not be available from those modules' context, and only callvirt.

Anyhow, that obviously doesn't alter anything in terms of functionality, Derived.BaseProperty will still really return "BASE_AWESOME", and thus this was not the root of our bug at work, simply a confusing component. I did however find it interesting how it could mislead developpers which would be unaware of that fact during their debug sessions, specially if Base is not exposed in your project but rather referenced as a 3rd party DLL, resulting in Devs just saying :

"Oi, wait..what ? omg that DLL is like, ..doing something funny"


Just found a nice little thing today:

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

This throws compile error.

The call to method 'Initialize' needs to be dynamically dispatched, but cannot be because it is part of a base access expression. Consider casting the dynamic arguments or eliminating the base access.

If I write base.Initialize(stuff as object); it works perfectly, however this seems to be a "magic word" here, since it does exactly the same, everything is still recieved as dynamic...


Assign This!


This is one that I like to ask at parties (which is probably why I don't get invited anymore):

Can you make the following piece of code compile?

    public void Foo()
    {
        this = new Teaser();
    }

An easy cheat could be:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

But the real solution is this:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

So it's a little know fact that value types (structs) can reassign their this variable.


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:

namespace Craft
{
    enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };


   class Mate
    {
        static void Main(string[] args)
        {

            JustTest(Symbol.Alpha); // enum
            JustTest(0); // why enum
            JustTest((int)0); // why still enum

            int i = 0;

            JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version

            JustTest(i); // it's ok from down here and below
            JustTest(1);
            JustTest("string");
            JustTest(Guid.NewGuid());
            JustTest(new DataTable());

            Console.ReadLine();
        }

        static void JustTest(Symbol a)
        {
            Console.WriteLine("Enum");
        }

        static void JustTest(object o)
        {
            Console.WriteLine("Object");
        }
    }
}

Here is an example of how you can create a struct that causes the error message "Attempted to read or write protected memory. This is often an indication that other memory is corrupt". The difference between success and failure is very subtle.

The following unit test demonstrates the problem.

See if you can work out what went wrong.

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

What will this function do if called as Rec(0) (not under the debugger)?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Answer:

  • On 32-bit JIT it should result in a StackOverflowException
  • On 64-bit JIT it should print all the numbers to int.MaxValue

This is because the 64-bit JIT compiler applies tail call optimisation, whereas the 32-bit JIT does not.

Unfortunately I haven't got a 64-bit machine to hand to verify this, but the method does meet all the conditions for tail-call optimisation. If anybody does have one I'd be interested to see if it's true.


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 return true if it is compared with null.

So a user of this API might have some code like this:

return test != null ? test : GetDefault();

or perhaps a bit more verbose, like this:

if (test == null)
    return GetDefault();
return test;

where GetDefault() is a method returning some default value that we want to use instead of null. The surprise hit me when I was using ReSharper and following it's recommendation to rewrite either of this to the following:

return test ?? GetDefault();

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 for null, not running operator= or Equals().


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.

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

It also equates to true if you check against string.Empty which means this op-code must have special behaviour to intern empty strings.


The scoping in c# is truly bizarre at times. Lets me give you one example:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

This fails to compile, because command is redeclared? There are some interested guesswork as to why it works that way in this thread on stackoverflow and in my blog.


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

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

Note that this does not work:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

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:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

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

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

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.


Consider this weird case:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

If Base and Derived are declared in the same assembly, the compiler will make Base::Method virtual and sealed (in the CIL), even though Base doesn't implement the interface.

If Base and Derived are in different assemblies, when compiling the Derived assembly, the compiler won't change the other assembly, so it will introduce a member in Derived that will be an explicit implementation for MyInterface::Method that will just delegate the call to Base::Method.

The compiler has to do this in order to support polymorphic dispatch with regards to the interface, i.e. it has to make that method virtual.


The following might be general knowledge I was just simply lacking, but eh. Some time ago, we had a bug case which included virtual properties. Abstracting the context a bit, consider the following code, and apply breakpoint to specified area :

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        d.Property = "AWESOME";
    }
}

class Base
{
    string _baseProp;
    public virtual string Property 
    { 
        get 
        {
            return "BASE_" + _baseProp;
        }
        set
        {
            _baseProp = value;
            //do work with the base property which might 
            //not be exposed to derived types
            //here
            Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
        }
    }
}

class Derived : Base
{
    string _prop;
    public override string Property 
    {
        get { return _prop; }
        set 
        { 
            _prop = value; 
            base.Property = value;
        } //<- put a breakpoint here then mouse over BaseProperty, 
          //   and then mouse over the base.Property call inside it.
    }

    public string BaseProperty { get { return base.Property; } private set { } }
}

While in the Derived object context, you can get the same behavior when adding base.Property as a watch, or typing base.Property into the quickwatch.

Took me some time to realize what was going on. In the end I was enlightened by the Quickwatch. When going into the Quickwatch and exploring the Derived object d (or from the object's context, this) and selecting the field base, the edit field on top of the Quickwatch displays the following cast:

((TestProject1.Base)(d))

Which means that if base is replaced as such, the call would be

public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }

for the Watches, Quickwatch and the debugging mouse-over tooltips, and it would then make sense for it to display "AWESOME" instead of "BASE_AWESOME" when considering polymorphism. I'm still unsure why it would transform it into a cast, one hypothesis is that call might not be available from those modules' context, and only callvirt.

Anyhow, that obviously doesn't alter anything in terms of functionality, Derived.BaseProperty will still really return "BASE_AWESOME", and thus this was not the root of our bug at work, simply a confusing component. I did however find it interesting how it could mislead developpers which would be unaware of that fact during their debug sessions, specially if Base is not exposed in your project but rather referenced as a 3rd party DLL, resulting in Devs just saying :

"Oi, wait..what ? omg that DLL is like, ..doing something funny"


Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

The output is "Attempted to read protected memory. This is an indication that other memory is corrupt."


I'm arriving a bit late to the party, but I've got three four five:

  1. If you poll InvokeRequired on a control that hasn't been loaded/shown, it will say false - and blow up in your face if you try to change it from another thread (the solution is to reference this.Handle in the creator of the control).

  2. Another one which tripped me up is that given an assembly with:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    if you calculate MyEnum.Red.ToString() in another assembly, and in between times someone has recompiled your enum to:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    at runtime, you will get "Black".

  3. I had a shared assembly with some handy constants in. My predecessor had left a load of ugly-looking get-only properties, I thought I'd get rid of the clutter and just use public const. I was more than a little surprised when VS compiled them to their values, and not references.

  4. If you implement a new method of an interface from another assembly, but you rebuild referencing the old version of that assembly, you get a TypeLoadException (no implementation of 'NewMethod'), even though you have implemented it (see here).

  5. Dictionary<,>: "The order in which the items are returned is undefined". This is horrible, because it can bite you sometimes, but work others, and if you've just blindly assumed that Dictionary is going to play nice ("why shouldn't it? I thought, List does"), you really have to have your nose in it before you finally start to question your assumption.


I'm not sure if you'd say this is a Windows Vista/7 oddity or a .Net oddity but it had me scratching my head for a while.

string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."

In Windows Vista/7 the file will actually be written to C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt


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.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using System.Runtime.Remoting.Messaging;

namespace BrokenProxy
{
    class NotAnIAsyncResult
    {
        public string SomeProperty { get; set; }
    }

    class BrokenProxy : RealProxy
    {
        private void HackFlags()
        {
            var flagsField = typeof(RealProxy).GetField("_flags", BindingFlags.NonPublic | BindingFlags.Instance);
            int val = (int)flagsField.GetValue(this);
            val |= 1; // 1 = RemotingProxy, check out System.Runtime.Remoting.Proxies.RealProxyFlags
            flagsField.SetValue(this, val);
        }

        public BrokenProxy(Type t)
            : base(t)
        {
            HackFlags();
        }

        public override IMessage Invoke(IMessage msg)
        {
            var naiar = new NotAnIAsyncResult();
            naiar.SomeProperty = "o noes";
            return new ReturnMessage(naiar, null, 0, null, (IMethodCallMessage)msg);
        }
    }

    interface IRandomInterface
    {
        int DoSomething();
    }

    class Program
    {
        static void Main(string[] args)
        {
            BrokenProxy bp = new BrokenProxy(typeof(IRandomInterface));
            var instance = (IRandomInterface)bp.GetTransparentProxy();
            Func<int> doSomethingDelegate = instance.DoSomething;
            IAsyncResult notAnIAsyncResult = doSomethingDelegate.BeginInvoke(null, null);

            var interfaces = notAnIAsyncResult.GetType().GetInterfaces();
            Console.WriteLine(!interfaces.Any() ? "No interfaces on notAnIAsyncResult" : "Interfaces");
            Console.WriteLine(notAnIAsyncResult is IAsyncResult); // Should be false, is it?!
            Console.WriteLine(((NotAnIAsyncResult)notAnIAsyncResult).SomeProperty);
            Console.WriteLine(((IAsyncResult)notAnIAsyncResult).IsCompleted); // No way this works.
        }
    }
}

Output:

No interfaces on notAnIAsyncResult
True
o noes

Unhandled Exception: System.EntryPointNotFoundException: Entry point was not found.
   at System.IAsyncResult.get_IsCompleted()
   at BrokenProxy.Program.Main(String[] args) 

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

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

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.


This one had me truly puzzled (I apologise for the length but it's WinForm). I posted it in the newsgroups a while back.

I've come across an interesting bug. I have workarounds but i'd like to know the root of the problem. I've stripped it down into a short file and hope someone might have an idea about what's going on.

It's a simple program that loads a control onto a form and binds "Foo" against a combobox ("SelectedItem") for it's "Bar" property and a datetimepicker ("Value") for it's "DateTime" property. The DateTimePicker.Visible value is set to false. Once it's loaded up, select the combobox and then attempt to deselect it by selecting the checkbox. This is rendered impossible by the combobox retaining the focus, you cannot even close the form, such is it's grasp on the focus.

I have found three ways of fixing this problem.

a) Remove the binding to Bar (a bit obvious)

b) Remove the binding to DateTime

c) Make the DateTimePicker visible !?!

I'm currently running Win2k. And .NET 2.00, I think 1.1 has the same problem. Code is below.

using System;
using System.Collections;
using System.Windows.Forms;

namespace WindowsApplication6
{
    public class Bar
    {
        public Bar()
        {
        }
    }

    public class Foo
    {
        private Bar m_Bar = new Bar();
        private DateTime m_DateTime = DateTime.Now;

        public Foo()
        {
        }

        public Bar Bar
        {
            get
            {
                return m_Bar;
            }
            set
            {
                m_Bar = value;
            }
        }

        public DateTime DateTime
        {
            get
            {
                return m_DateTime;
            }
            set
            {
                m_DateTime = value;
            }
        }
    }

    public class TestBugControl : UserControl
    {
        public TestBugControl()
        {
            InitializeComponent();
        }

        public void InitializeData(IList types)
        {
            this.cBoxType.DataSource = types;
        }

        public void BindFoo(Foo foo)
        {
            this.cBoxType.DataBindings.Add("SelectedItem", foo, "Bar");
            this.dtStart.DataBindings.Add("Value", foo, "DateTime");
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.cBoxType = new System.Windows.Forms.ComboBox();
            this.dtStart = new System.Windows.Forms.DateTimePicker();
            this.SuspendLayout();
            //
            // checkBox1
            //
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(14, 5);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(97, 20);
            this.checkBox1.TabIndex = 0;
            this.checkBox1.Text = "checkBox1";
            this.checkBox1.UseVisualStyleBackColor = true;
            //
            // cBoxType
            //
            this.cBoxType.FormattingEnabled = true;
            this.cBoxType.Location = new System.Drawing.Point(117, 3);
            this.cBoxType.Name = "cBoxType";
            this.cBoxType.Size = new System.Drawing.Size(165, 24);
            this.cBoxType.TabIndex = 1;
            //
            // dtStart
            //
            this.dtStart.Location = new System.Drawing.Point(117, 40);
            this.dtStart.Name = "dtStart";
            this.dtStart.Size = new System.Drawing.Size(165, 23);
            this.dtStart.TabIndex = 2;
            this.dtStart.Visible = false;
            //
            // TestBugControl
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.dtStart);
            this.Controls.Add(this.cBoxType);
            this.Controls.Add(this.checkBox1);
            this.Font = new System.Drawing.Font("Verdana", 9.75F,
            System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
            ((byte)(0)));
            this.Margin = new System.Windows.Forms.Padding(4);
            this.Name = "TestBugControl";
            this.Size = new System.Drawing.Size(285, 66);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox checkBox1;
        private System.Windows.Forms.ComboBox cBoxType;
        private System.Windows.Forms.DateTimePicker dtStart;
    }

    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            InitializeControl();
        }

        public void InitializeControl()
        {
            TestBugControl control = new TestBugControl();
            IList list = new ArrayList();
            for (int i = 0; i < 10; i++)
            {
                list.Add(new Bar());
            }
            control.InitializeData(list);
            control.BindFoo(new Foo());
            this.Controls.Add(control);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }

        #endregion
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

What will this function do if called as Rec(0) (not under the debugger)?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Answer:

  • On 32-bit JIT it should result in a StackOverflowException
  • On 64-bit JIT it should print all the numbers to int.MaxValue

This is because the 64-bit JIT compiler applies tail call optimisation, whereas the 32-bit JIT does not.

Unfortunately I haven't got a 64-bit machine to hand to verify this, but the method does meet all the conditions for tail-call optimisation. If anybody does have one I'd be interested to see if it's true.


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


This is one of the most unusual i've seen so far (aside from the ones here of course!):

public class Turtle<T> where T : Turtle<T>
{
}

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]


The following prints False instead of throwing an overflow exception:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}

Just found a nice little thing today:

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

This throws compile error.

The call to method 'Initialize' needs to be dynamically dispatched, but cannot be because it is part of a base access expression. Consider casting the dynamic arguments or eliminating the base access.

If I write base.Initialize(stuff as object); it works perfectly, however this seems to be a "magic word" here, since it does exactly the same, everything is still recieved as dynamic...


VB.NET, nullables and the ternary operator:

Dim i As Integer? = If(True, Nothing, 5)

This took me some time to debug, since I expected i to contain Nothing.

What does i really contain? 0.

This is surprising but actually "correct" behavior: Nothing in VB.NET is not exactly the same as null in CLR: Nothing can either mean null or default(T) for a value type T, depending on the context. In the above case, If infers Integer as the common type of Nothing and 5, so, in this case, Nothing means 0.


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

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

Note that this does not work:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

The following prints False instead of throwing an overflow exception:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}

This one is pretty straightforward but I still find it somewhat interesting. What would be the value of x after the call to Foo?

static int x = 0;

public static void Foo()
{
    try { return; }
    finally { x = 1; }
}

static void Main() { Foo(); }

PropertyInfo.SetValue() can assign ints to enums, ints to nullable ints, enums to nullable enums, but not ints to nullable enums.

enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!

Full description here


I'm arriving a bit late to the party, but I've got three four five:

  1. If you poll InvokeRequired on a control that hasn't been loaded/shown, it will say false - and blow up in your face if you try to change it from another thread (the solution is to reference this.Handle in the creator of the control).

  2. Another one which tripped me up is that given an assembly with:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    if you calculate MyEnum.Red.ToString() in another assembly, and in between times someone has recompiled your enum to:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    at runtime, you will get "Black".

  3. I had a shared assembly with some handy constants in. My predecessor had left a load of ugly-looking get-only properties, I thought I'd get rid of the clutter and just use public const. I was more than a little surprised when VS compiled them to their values, and not references.

  4. If you implement a new method of an interface from another assembly, but you rebuild referencing the old version of that assembly, you get a TypeLoadException (no implementation of 'NewMethod'), even though you have implemented it (see here).

  5. Dictionary<,>: "The order in which the items are returned is undefined". This is horrible, because it can bite you sometimes, but work others, and if you've just blindly assumed that Dictionary is going to play nice ("why shouldn't it? I thought, List does"), you really have to have your nose in it before you finally start to question your assumption.


This is the strangest I've encountered by accident:

public class DummyObject
{
    public override string ToString()
    {
        return null;
    }
}

Used as follows:

DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);

Will throw a NullReferenceException. Turns out the multiple additions are compiled by the C# compiler to a call to String.Concat(object[]). Prior to .NET 4, there is a bug in just that overload of Concat where the object is checked for null, but not the result of ToString():

object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;

This is a bug by ECMA-334 §14.7.4:

The binary + operator performs string concatenation when one or both operands are of type string. If an operand of string concatenation is null, an empty string is substituted. Otherwise, any non-string operand is converted to its string representation by invoking the virtual ToString method inherited from type object. If ToString returns null, an empty string is substituted.


Here's one I only found out about recently...

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

The above looks crazy at first glance, but is actually legal.No, really (although I've missed out a key part, but it isn't anything hacky like "add a class called IFoo" or "add a using alias to point IFoo at a class").

See if you can figure out why, then: Who says you can’t instantiate an interface?


From a question I asked not long ago:

Conditional operator cannot cast implicitly?

Given:

Bool aBoolValue;

Where aBoolValue is assigned either True or False;

The following will not compile:

Byte aByteValue = aBoolValue ? 1 : 0;

But this would:

Int anIntValue = aBoolValue ? 1 : 0;

The answer provided is pretty good too.


What will this function do if called as Rec(0) (not under the debugger)?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Answer:

  • On 32-bit JIT it should result in a StackOverflowException
  • On 64-bit JIT it should print all the numbers to int.MaxValue

This is because the 64-bit JIT compiler applies tail call optimisation, whereas the 32-bit JIT does not.

Unfortunately I haven't got a 64-bit machine to hand to verify this, but the method does meet all the conditions for tail-call optimisation. If anybody does have one I'd be interested to see if it's true.


Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

The output is "Attempted to read protected memory. This is an indication that other memory is corrupt."