runtime: DefaultValueAttribute missing unsigned int / unsigned long constructor

Latest proposal

Rationale and Usage

As has already been explained, using DefaultValueAttribute with one of the problematic types (unsigned integer types and sbyte) in C# ends up using a widening conversion and so the boxed Value ends up with an unexpected type. The proposal is to add constructor overloads so that the conversions don’t happen and Value gets the expected type.

The usage stays the same as before, e.g. [DefaultValue(UInt64.MaxValue)].

Doing this would be technically a source breaking change, since recompiling existing code would end up with a different type for the boxed Value. (Arguably, it would be a better type, but that doesn’t change the fact that someone could rely on the old behavior.)

Proposed API

public class DefaultValueAttribute : Attribute
{
    // existing constructor overloads:
    public DefaultValueAttribute(Type type, string value);
    public DefaultValueAttribute(char value);
    public DefaultValueAttribute(byte value);
    public DefaultValueAttribute(short value);
    public DefaultValueAttribute(int value);
    public DefaultValueAttribute(long value);
    public DefaultValueAttribute(float value);
    public DefaultValueAttribute(double value);
    public DefaultValueAttribute(bool value);
    public DefaultValueAttribute(string value);
    public DefaultValueAttribute(object value);

    // added constructor overloads:
    public DefaultValueAttribute(sbyte value);
    public DefaultValueAttribute(ushort value);
    public DefaultValueAttribute(uint value);
    public DefaultValueAttribute(ulong value);
}

Original proposal

Most numeric types have their constructor but not the unsigned ones.

As a result, if you write that code: new DefaultValueAttribute(UInt64.MaxValue);

The float constructor will be called as the compiler seems to avoid the constructor that needs boxing.

Removing all explicit constructor that takes numeric types solve the issue.

They all points to the same code that will box the value anyway:

/// <devdoc>
/// <para>Initializes a new instance of the <see cref='System.ComponentModel.DefaultValueAttribute'/> class using a Unicode
///    character.</para>
/// </devdoc>
public DefaultValueAttribute(char value) {
    this.value = value;
}

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 15 (12 by maintainers)

Commits related to this issue

Most upvoted comments

My API proposal speclet:

Rationale and Usage

As has already been explained, using DefaultValueAttribute with one of the problematic types (unsigned integer types and sbyte) in C# ends up using a widening conversion and so the boxed Value ends up with an unexpected type. The proposal is to add constructor overloads so that the conversions don’t happen and Value gets the expected type.

The usage stays the same as before, e.g. [DefaultValue(UInt64.MaxValue)].

Doing this would be technically a source breaking change, since recompiling existing code would end up with a different type for the boxed Value. (Arguably, it would be a better type, but that doesn’t change the fact that someone could rely on the old behavior.)

Proposed API

public class DefaultValueAttribute : Attribute
{
    // existing constructor overloads:
    public DefaultValueAttribute(Type type, string value);
    public DefaultValueAttribute(char value);
    public DefaultValueAttribute(byte value);
    public DefaultValueAttribute(short value);
    public DefaultValueAttribute(int value);
    public DefaultValueAttribute(long value);
    public DefaultValueAttribute(float value);
    public DefaultValueAttribute(double value);
    public DefaultValueAttribute(bool value);
    public DefaultValueAttribute(string value);
    public DefaultValueAttribute(object value);

    // added constructor overloads:
    public DefaultValueAttribute(sbyte value);
    public DefaultValueAttribute(ushort value);
    public DefaultValueAttribute(uint value);
    public DefaultValueAttribute(ulong value);
}```