none
Possibly unboxing a null reference - Nullables

    Question

  • Hi,

    The static checker warns about both lines in the Main method below, but it should probably only warn about the first line.

    using System;
    using System.Diagnostics.Contracts;
    
    namespace TestContracts
    {
      class Program
      {
        static void Main()
        {
          int first = (int) Foo();
          int second = (int?) Foo() ?? 55;
        }
    
        static object Foo()
        {
          return null;
        }
      }
    }

        Warning 1 CodeContracts: Possibly unboxing a null reference [file] 10 7 TestContracts
        Warning 2 CodeContracts: Possibly unboxing a null reference [file] 11 7 TestContracts
        Message 3 CodeContracts: Checked 6 assertions: 4 correct 2 unknown [program] 1 1 TestContracts

    Thanks, 
    Dave
    Monday, March 15, 2010 3:00 AM

Answers

All replies

  • I think that if you mark Foo() as Pure then this is the case, otherwise the checker can't determine that Foo() always returns the same result each invocation.
    Monday, March 15, 2010 3:53 PM
  • Hi,

    Hmm, but Foo is not necessarily pure in my real code.

    I think the real problem is simply that CC doesn't understand this pattern: cast a value-type to a nullable and use the null coalescing operator to provide a default value for null.

    This is a common pattern in C# that allows us to succinctly read a value-type and provide a default value to replace null, without having to worry about potentially unboxing a null reference.

    It's especially useful when working with untyped dictionaries that return null for missing items, such as NameValueCollection.  Take session state in ASP.NET for example:

    private int CurrentCount
    {
      get
      {
        return (int?) Session["CurrentCount"] ?? 0;
      }
    }

    The code above will never unbox a null reference.  If the session state does not contain a value for CurrentCount, then it will return null and the CurrentCount property will return 0 (zero).

    Thanks, 
    Dave
    http://davesexton.com/blog
    Monday, March 15, 2010 6:57 PM
  • Looking at what the second compiles to, you can see the problem is the unbox of object to 'int?' that can be null, not the nullable's result unboxing to int being null.  The value type Nullable<int> can't be null (struct) so this is the reason for the warning.
                int? foo = (int?)Foo();            
                int second;
                if (foo.HasValue)
                {
                    second = 55;
                }
                second = foo.GetValueOrDefault();


    Monday, March 15, 2010 9:32 PM
  • Hi,

    > you can see the problem is the unbox of object to 'int?'

    No, the problem is that CC doesn't understand this pattern.

    There is an implicit conversion from null to Nullable<T>.

    § Implicit Conversions
    http://msdn.microsoft.com/en-us/library/2cf62fcy(VS.80).aspx

    > The value type Nullable<int> can't be null (struct)

    This just confirms my point that CC doesn't understand this valid pattern.

    Thanks, 
    Dave
    http://davesexton.com/blog
    Monday, March 15, 2010 10:41 PM
  • Hello,

      I've tried the example with the last internal version of the static checker, and it seems to me it's working as expected.

    Best,

    f

    Thursday, February 17, 2011 2:07 AM
    Owner
  • This is still a problem with the latest version, for example:

            public static T? Test<T>(string value) where T : struct
            {
                var conv = TypeDescriptor.GetConverter(typeof(T));
                Contract.Assume(conv != null);
                return (T?)conv.ConvertFrom(value); // warning here
            }


    Wednesday, May 16, 2012 9:54 AM