3

派生クラスからその基本クラスに属性引数を渡すことは可能ですか?

基本的に、派生クラスからプロパティの属性の引数を設定しようとしています。

  • C++ でそれを行う方法

    public class HasHistory<T, string name> {
        public HasHistory() {
            History=new History<T>();
        }
    
        // here's my attribute
        [BsonElement(name)]
        public History<T> History {
            get;
            protected set;
        }
    }
    

    ただし、型以外のテンプレート引数は C++ では有効ですが、C#では無効です。

  • C# での予期せぬ回避策

    プロパティを仮想化し、派生クラスに属性を追加できることに気付きました。しかし、コンストラクターで仮想関数を呼び出すことになります。それはうまくいくかもしれませんが、それは悪い習慣です。

    基本クラスのコンストラクターでメンバーを初期化する必要があるため、その呼び出しを行いたいと思います。実際、それが基本クラスの要点です。

    public class HasHistory<T> {
        public HasHistory() {
            // this will be called before Derived is constructed
            // and so the vtbl will point to the property method
            // defined in this class.
            // We could probably get away with this, but it smells.
            History=new History<T>();
        }
    
        // here's my property, without an Attribute
        public virtual History<T> History {
            protected set;
            get;
        }
    }
    
    public class Derived: HasHistory<SomeType> {
        // crap! I made this virtual and repeated the declaration
        // just so I could add an attribute!
        [BsonElement("SomeTypeHistory")]
        public virtual HasHistory<SomeType> History {
            protected set;
            get;
        }
    }
    

    したがって、属性をベースに配置することはできず、代わりに、保護されたベースクラスのプロパティの観点から実装されている/使用する派生クラスのプロパティに配置することはできなかったと思いますが、それは面倒なので、ベースを使用することによって得られる利便性を排除しますクラス。

これを行う良い方法がありますよね?右?

派生クラスのプロパティをオーバーライドせずに、ベースから継承する派生クラスのプロパティの属性を再定義するにはどうすればよいですか?

4

1 に答える 1

0

更新:くそー、あなたはすでにこれを検討しました。投稿する前に更新する必要がありました:)

残念ながら、やりたいことは、C# の属性メカニズムの範囲外です。ジェネリックはテンプレートとは異なるため、この種の回避策はほぼ同じです。

ほとんどの場合、最上位で属性を定義することになるため、一般的にはこれは問題になりません。それ問題である場合(明らかにあなたの場合のように)、醜い回避策を使用する必要があります。

以下の元の回答...


例を正しく理解していれば、派生型で宣言された値に基づいてクラスメンバーに属性を適用したいと考えています。C# は Generics の非型パラメーターをサポートしていないため、これを行うには別の方法が必要です。

できることの 1 つは、次のように子孫クラス内のプロパティをオーバーライドすることです。

public class HasHistory<T>
{
    public HasHistory() 
    {
        History = new History<T>();
    }

    public virtual History<T> History { get; protected set; }
}

public class MyHistory<T> : HasHistory<T>
{
    public MyHistory()
        : base()
    {}

    [BSONElement("some name")]
    public override History<T> History 
    { 
        get
        {
            return base.History;
        }
        protected set
        {
            base.History = value;
        }
    }
}

BsonElement属性を使用するコードは、派生インスタンスの実際の型で動作するため、チェーンの最後で定義された属性を調べます。上記のコードの場合、インスタンスを作成して BSON シリアライザーに渡すと、クラス内のプロパティにアタッチされた属性が検出されます。HasHistory<T>virtualMyHistory<T>HistoryMyHistory<T>

ただし、基本レベルで属性を定義し、必要に応じて派生クラスでオーバーライドすることができます。これがあなたの場合に役立つかどうかはわかりません。

特に各派生クラスでこれを行う必要があるため、より多くの作業が必要ですが、この場合、C++ テンプレート スタイルに到達するのと同じくらい近いと思います。ただし、間違っていることが証明されれば幸いです:)

于 2013-03-15T05:21:13.113 に答える