私は次のように定義されたカスタム属性を持っています:
[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
public string Description { get; private set; }
public string Code { get; private set; }
public EnumDisplayAttribute(string description = null, string code = null)
{
Description = description;
Code = code;
}
}
両方のコンストラクターパラメーターはオプションです。
このようなフィールドでこの属性を使用する場合
public enum TransactionType
{
[EnumDisplay(code: "B")]
Bill,
[EnumDisplay(description: null, code: "C")]
CashReceipt,
}
コードエディタに波線は表示されませんが、ファイル行番号の列がない漠然としたエラーが表示されます。エラーメッセージは次のとおりです。
エラーCS0182:属性引数は、定数式、typeof式、または属性パラメーターtypeの配列作成式である必要があります
エラーをクリックしても何も起こりません。つまり、エラーサイトに移動することはありません(明らかに、行番号と列がないため)。
次のように属性を設定した場合でも、次のようになります。
[EnumDisplay("This is a Bill")]
コンパイラはそれを好きではありません。
事実上、この属性を属性として使用するために、両方のパラメーター(名前付きかどうか)を指定する必要があります。
もちろん、この属性を次のように通常のクラスとして使用する場合:
var enumDisplayAttribute = new EnumDisplayAttribute();
enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill");
enumDisplayAttribute = new EnumDisplayAttribute(code: "B");
enumDisplayAttribute = new EnumDisplayAttribute(description: "This is a Bill", code: "B");
enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill", "B");
enumDisplayAttribute = new EnumDisplayAttribute("This is a Bill");
コンパイラは、上記の「スタイル」のいずれかを受け入れます。
確かに、何かが足りないか、脳が機能していないだけです。
属性のオプション値がC#にすでに存在していた後、オプションのパラメーターがC#に追加されました。したがって、オプションの属性パラメーターについては、属性固有の構文にフォールバックする必要があります。
_[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
public string Description { get; set; }
public string Code { get; set; }
public EnumDisplayAttribute()
{
}
}
public enum TransactionType
{
[EnumDisplay(Code = "B")]
Bill,
[EnumDisplay(Description = null, Code = "C")]
CashReceipt,
}
_
ご覧のとおり、最終結果は事実上同じですが、名前付き引数を使用する代わりに、名前付きプロパティを使用しています([EnumDisplay(Description = null, Code = "C")]
のような構文は属性宣言でのみ可能です)。
別の見方をすれば、属性宣言はメソッド/コンストラクターの呼び出しから構文を「借用」しますが、属性宣言はそれ自体メソッドの呼び出しではないため、メソッドと同じ機能をすべて取得するわけではありません。 。
コンストラクターを使用して値を属性にプッシュしたい場合(たとえば、属性のプロパティの一部が必須である場合、またはそれらに対して何らかの処理を実行する場合)、いつでも古い学校に行ってコンストラクターをオーバーロードできます。
例えば:
[AttributeUsage(AttributeTargets.Field)]
public class SampleAttribute : Attribute
{
public string MandatoryProperty { get; private set; }
public string OptionalProperty { get; private set; }
// we use an overload here instead of optional parameters because
// C# does not currently support optional constructor parameters in attributes
public SampleAttribute(string mandatoryProperty)
: this(mandatoryProperty, null)
{
}
public SampleAttribute(string mandatoryProperty, string optionalProperty)
{
MandatoryProperty = mandatoryProperty;
OptionalProperty = optionalProperty;
}
}
オプションのパラメーターは実際にはオプションではなく、メソッドのシグネチャにはすべての引数が含まれ、属性は特別です(オプションのパラメーターの前に存在し、属性として適用されると異なるルールがあります(たとえば、誰が属性コンストラクターを呼び出すかを検討してください))。ただし、将来的にはサポートが追加されると思います。
今のところ、オプションの効果を実現したい場合は、次のことを試してください。
[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayAttribute : Attribute
{
public string Description { get; set; }
public string Code { get; set; }
}
そして、そのように適用します:
[EnumDisplay(Description = null, Code = "C")]
private object _aField;