Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using default keyword in a DLL

Tags:

c#

mono

default

I've run into a really strange problem when using the default keyword in a DLL project. In my DLL project (compiled with VS2013) I have the following class:

public class BaseClass<T>
{
    public T value;
    public bool enabled;

    public BaseClass ( T value = default(T), bool enabled = true )
    {
        this.value = value;
        this.enabled = enabled;
    }
}

Now, if I use this inside the DLL project, it works perfectly. I can create classes that derive from this base class without issue. But, as soon as I try to use the DLL in another project (compiled with Mono 2.0.0), deriving from the base class with a value type causes a compiler error. This:

public class ChildClass : BaseClass<int>
{
}

causes this:

Assets/ChildClass.cs(8,14): error CS1502: The best overloaded method match for BaseClass<int>.BaseClass(int, bool)' has some invalid arguments

Assets/ChildClass.cs(8,14): error CS1503: Argument #1' cannot convertnull' expression to type `int'

However, the base class with value types can be used in fields without an issue:

public class OtherClass
{
    public BaseClass<int> baseInt;
}

I looked at the DLL using ILSpy and noticed this:

public class BaseClass<T>
{
    public T value;
    public bool enabled;
    public BaseClass(T value = null, bool enabled = true)
    {
        this.value = value;
        this.enabled = enabled;
    }
}

Note that default<T> in the constructor has been replaced with null. This seems to be the cause of the problem, as null would be an invalid value for a value type.

So what's going on here?

EDIT: As discovered in the comments, this doesn't occur when the second project is compiled with VS2013, or with newer versions of Mono.

like image 773
Adam Avatar asked Nov 05 '14 17:11

Adam


1 Answers

This seems to be a bug with the mono compiler pre-3.2.3 (@usr was quite right in their initial comment). The compiler inserts default parameter values into the assembly metadata as attributes (see this answer). I verified the output of ilspy is consistent with ildasm which encodes the default(T) to .param [1] = nullref. I suspect the convention is that a generic default(T) is encoded as null and the consuming compiler is just supposed to know how to use that. It seems related to this issue, however, based on the dates, this particular issue was fixed some time before that was reported.

like image 137
Mike Zboray Avatar answered Oct 15 '22 14:10

Mike Zboray