カスタム属性を制限して、C#の特定のタイプにのみ適用できるようにしますか?
-
06-07-2019 - |
質問
クラスのプロパティとクラス自体に適用されるカスタム属性があります。これで、カスタム属性を適用する必要があるすべてのクラスが単一の基本クラスから派生します。
カスタム属性を制限して、基本クラスから派生する必要があるクラスのみに適用できるようにするにはどうすればよいですか?どうすればいいですか?
解決
いや、自分が間違っていることを証明するのは嫌いです...属性をベースクラスのネストされた保護型として定義すると機能します:
abstract class MyBase {
[AttributeUsage(AttributeTargets.Property)]
protected sealed class SpecialAttribute : Attribute {}
}
class ShouldBeValid : MyBase {
[Special]
public int Foo { get; set; }
}
class ShouldBeInvalid {
[Special] // type or namespace not found
[MyBase.Special] // inaccessible due to protection level
public int Bar{ get; set; }
}
(元の回答)
これはできません-少なくともコンパイル時ではありません。
属性は、(例として)" class"、" struct"、" method"、" field"などに制限できますが、それ以上の粒度はありません。
もちろん、属性はそれ自体では何もしないため(PostSharpを無視)、他の型に対しては不活性になります(実行時に属性を調べるコードを追加しない限り、型に対しては不活性になります)。
FxCopルールを記述できますが、それはやり過ぎのようです。
ただし、属性が最良の選択かどうかは疑問です:
カスタム属性を適用する必要があるすべてのクラスは、単一の基本クラスから派生しています。
カスタム属性を適用する必要がある場合 、おそらく abstract
(または virtual
)プロパティ/メソッドがより良い選択でしょうか?
abstract class MyBase {
protected abstract string GetSomeMagicValue {get;}
}
class MyActualType : MyBase {
protected override string GetSomeMagicValue {get {return "Foo";}}
}
他のヒント
カスタム属性を使用してこれを行う方法を知りません。
より良い方法は、クラスに一般的な制約を持つインターフェイスを実装させることです
そう
class MyAttribute
{
// put whatever custom data you want in here
}
interface IAttributeService<T> where T : MyBaseClass
{
MyAttribute Value{get;}
}
基本クラスはこれを行います
class MyBaseClass : IAttributeService<MyBaseClass>
{
private MyAttribute m_attrib;
IAttributeService<MyClass>.Value
{
get {return m_attrib;}
}
}
そのようにしてコンパイラはコンパイル時に制約を適用し、クラスのみ
MyBaseClassから派生したインターフェイスを実装できます。
MyAttributeクラスを定義することでかなり拡張可能にしましたが、もちろん、もっとシンプルなものが必要な場合は文字列またはブール値を返すことができます
また、MyAttributeメンバーをプライベートにしたので、派生クラスはそれを表示および変更できませんが、必要に応じて保護し、派生クラスへのアクセスを許可できます。