سؤال

I have the following code as part of a system for generating interfaces using reflection.emit

void IPropertyCreator.AddAttribute<T>(params object[] args)
{
    // Convert args to types
    var argTypes = new Type[args.Length];
    for (int i = 0; i < args.Length; ++i)
    {
        argTypes[i] = args[i] != null ? args[i].GetType() : null;
    }
    // Get constructor
    var ctorInfo = typeof(T).GetConstructor(argTypes);

    // Create custom attribute
    var attrBuilder = new CustomAttributeBuilder(ctorInfo, args);
    _propertyBuilder.SetCustomAttribute(attrBuilder);
}

In the case with an issue, I am creating an attribute (The T typeparam) with a constructor taking a single object parameter and the argument is a decimal The attribute has (only) the following constructor

public DefaultValueAttribute(object value)

This code works fine with all POD types (byte, char, int, etc) and also string but fails when using decimal. The constructor of CustomAttributeBuilder fails with exception "Passed in argument value at index 0 does not match the parameter type".

Debugging shows that all the variables are as expected:
args has one element of type object{decimal}
argTypes has one element Type = System.Decimal
ctorInfo has correctly selected the (only) constructor which takes an object parameter.

I have demonstrated that the attribute can be instantiated by passing a decimal parameter directly:

decimal val = 123.456M;
var attr = new DefaultValueAttribute(val);

I have tried converting the decimal to an object and a System.Decimal to no effect. I suspect the issue is related to the fact that decimal is not a POD type as such but a structure.

I tried adding a constructor overload to the attribute (taking decimal type). The above function picked up the new constructor correctly but then failed in the same place with the exception "An invalid type was used as a custom attribute constructor argument, field or property"

Does anyone have any ideas how I can work around this?

هل كانت مفيدة؟

المحلول

Just try to write this in plain C# code:

class TestAttribute : Attribute {
    public TestAttribute(object value) { }
}

[Test(1.2m)]         // NOTE: CS0182
class Example { }

You simply can't use System.Decimal for attribute constructor arguments. Double is okay. Section 17.1.3 of the C# language specification hints at the problem but isn't too specific about this particular case. System.Decimal is a bit of a step-child of the standard value types. It is never mentioned in the Ecma 335 for example. The C# compiler makes it look like a basic type but the CLR doesn't treat it the same way.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top