1

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);
}

T問題が発生した場合、単一のパラメーターを受け取るコンストラクターを使用して 属性 (typeparam) を作成していますobject。引数はdecimal 次のコンストラクター (のみ) を持っています。

public DefaultValueAttribute(object value)

このコードは、すべての POD タイプ ( bytecharintなど) で正常にstring機能しますが、 を使用すると失敗しdecimalます。のコンストラクターは、「インデックス 0 で渡された引数値がパラメーターの型と一致しません」というCustomAttributeBuilder例外で失敗します。

デバッグは、すべての変数が期待どおりであることを示しています:
argstype の 1 つの要素を持っています 1 つの要素をobject{decimal}
argTypes持っています Type =System.Decimal
ctorInfoオブジェクト パラメーターを取る (唯一の) コンストラクターを正しく選択しました。

10 進数のパラメーターを直接渡すことで、属性をインスタンス化できることを示しました。

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

小数を an に変換し、objectaを無効にしようとしましたSystem.Decimaldecimalこの問題は、それ自体が POD タイプではなく、構造であるという事実に関連していると思われます。

属性にコンストラクターのオーバーロードを追加しようとしました(decimal型を取ります)。上記の関数は新しいコンストラクターを正しく取得しましたが、同じ場所で「カスタム属性コンストラクターの引数、フィールド、またはプロパティとして無効な型が使用されました」という例外で失敗しました。

これを回避する方法を知っている人はいますか?

4

1 に答える 1

4

これを単純な C# コードで記述してみてください。

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

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

属性コンストラクターの引数に System.Decimal を使用することはできません。ダブルで大丈夫です。C# 言語仕様のセクション 17.1.3 は問題を示唆していますが、この特定のケースについてあまり具体的ではありません。System.Decimal は、標準値型の継子のようなものです。たとえば、Ecma 335 では言及されていません。C# コンパイラでは基本型のように見えますが、CLR では同じようには扱われません。

于 2013-08-24T14:14:47.550 に答える