Conditional operator bug in .NET 1.x & 2.0

Update: This behavior is as expected according to the .NET team but it's probably unexpected for most users.

I encountered a strange problem this week when a conditional operator appeared to be evaluating the false expression contrary to the C# documentation. The line looked like:

return testObject == null ? null : testObject.InstanceVariable;

The point of this line is to prevent accessing .InstanceVariable if the object is null and yet every time this line executed a NullReferenceException is thrown (and no I wasn’t overloading the == operator).

With a little experimentation I was able to narrow it down and produce a simple test case that exercised the bug on .NET 1.1 and .NET 2.0.

The problem is this: If the return parts are not of the same type and one of the members supports implicit conversion to the expect type, then it is called regardless of whether it is the the true part or not.

I filed the bug with Microsoft and it was confirmed last night by one of their C# engineers, there is a small chance it will be fixed in .NET 2.0 before release but we’ll have to see. I checked out some of the .NET classes and they too always access the object during an implicit conversion, however they are all value types which can not be null.

In the mean time there is an easy way to avoid this by modifying your implicit conversion methods to check for null before converting.

public static implicit operator string(ClassWithImplicitConversion objToConvert) {
    return objToConvert == null ? string.Empty : objToConvert.ToString();
}

A full test case appears below:

using System;

namespace ProveConditionalBug {
     class Program {
         static void Main(string[] args) {
             Console.Out.WriteLine("Testing... " + ProveConditional());
         }

        static string ProveConditional() {
            ClassHoldingImplicitConversionMember testObject = null;
            return (testObject == null) ? null : testObject.InstanceVariable;
        }
     }

    class ClassHoldingImplicitConversionMember {
        public ClassWithImplicitConversion InstanceVariable = null;<br />     }

    class ClassWithImplicitConversion {
         public string Value = "Test";
         public static implicit operator string(ClassWithImplicitConversion objToConvert) {
             return objToConvert.Value;
         }
     }
}

[)amien

0 responses