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:
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.