2016-04-30 10 views
1

okこれは簡単な質問ではありません。あなたが自己参照、ジェネリッククラス、静的コンストラクタでクラスの型を取得します。

ような何かを行うときに

public class ClassA : BaseClass<ClassA>{ 
} 
public abstract class BaseClass<T> where T : BaseClass<T> { 
    static readonly int _aValue; 
    static BaseClass(){ 
     //here i have code that load _avalue for each kind of T type, based on my own logic 
     _aValue=1; 

     //need to get the real type here 
    } 
    public int GetValue() { 
     return _aValue; 
    } 
} 


ClassA c = new ClassA(); 
Console.WriteLine(c.GetValue()); 

:私は必要なもの

は、あなたがこのようなコードを持っている想像自己参照でクラスの型を取得する方法、ジェネリッククラス、静的コンストラクタ

です起こる何ここ

ClassA c = new ClassA(); 
Console.WriteLine(c.GetValue()); 

は、静的コンストラクタが呼び出されます、それは静的変数

0123に私の例では値をロードすることですT型は、実際にClassA

であれば、私は、コンストラクタを呼び出すのタイプがあれば、静的コンストラクタに知っておく必要があります(ジェネリック型のコンストラクタで各派生クラスはそれを呼び出すので、私は私が必要なものを行うことができます仮定)

私の本当の必要性は、私は正しく私のクラス定義を宣言した場合、私は私のテストでは、私が見つけたので、自己参照型が本当の自己参照されていることを確実にする良い方法を見つけることがありますので、知っている

ClassX : Message<ClassAAA> 

doesnのこと私は強制したいと思う間にエラーが起きる

ClassA : Message<ClassA> 
ClassB : Message<ClassB> 
ClassC : Message<ClassC> 

なく

ClassD : Message<DifferentClass> 

任意の手掛かり?

私はすでにMethodInfo.GetMethod()。DeclaringTypeを使用してみましたが、それは基本クラスを返し

UPDATE OK私は、私はこの種の設計を使用して、私のシナリオでは もう少し説明してみましょうクライアント/サーバのシナリオで使用するカスタムメッセージ定義を持っていて、それぞれの異なるメッセージ派生クラスには「メッセージID」を指定するバイトが必要です。そのため、属性を使用してクラスを修飾し、その属性を使用して、私はコードの周りに魔法の番号を持っていない)

私の静的なコンストラクタメッセージベースクラスは、リフレクションを使用して属性値を読み込んで静的な_aValueメンバーに格納するため、あらゆる種類のMessageに独自のメッセージIDがあり、パフォーマンスの理由から、すべてのメッセージタイプで一度だけロードされます。 。 私が

[MyAttribute(MyMessages.Ping)] 
public class PingMessage : Message<PingMessage> 

と私のPingMessageクラスがistantiatedされるたびに、私はその静的messageTye値を取得することができますし、私はそれで満足しているようなクラスを聞かせて持っていると言うことができ、非常にうまく機能し、問題が時々起こるということですその間違いを、私はAnotherMessageが、それは合法ですので、メッセージを継承別のクラスであるため、コンパイル時エラーが上昇しない

[MyAttribute(MyMessages.Ping)] 
public class PingMessage : Message<AnotherMessage> 

とジェネリック制約ようなクラスを作成しますが、私は、もしことを強制したいのであなたはMessageから継承しています。Tは継承するクラスでなければならないので、ただ許可してください

PingMessage : Message<PingMessage> 

私はこれを行うための一般的な制約はないことを知っています。もちろん、作成するメッセージがわからないため、派生クラスを制約に追加することはできませんとにかくたくさんのメッセージを持っていると意味がありません)、メッセージ型の静的コンストラクタの中で私の型制約チェックをしたかったのです。私は既にそこで何かをしていて、私には型が間違っていないか、クラスに属性が指定されていない場合に例外が発生する

技術的には、私のインスタンスコンストラクタでこの種のチェックを行うことができますが、パフォーマンスは重要です。

メッセージがカスタムインターフェイスを実装していて、タイプをチェックして初期化中にしか呼び出せないメソッドがあると思っていましたが、できるだけ簡単なアプローチを探していましたが、 「tは私が宣言されてからclass X : Message<Y>を防ぐ方法を知りませんが、あなただけのあなたが欲しいものにMessageサブタイプの使用を制限することができ、ここで

+0

'if(c is ClassA)'? [MSDN](https://msdn.microsoft.com/en-us/library/scekt9xw.aspx) - この例は、探しているパターンと一致するようです。 –

+0

静的コンストラクターでは静的であり、どの型でも呼び出されないため、そのことを知ることはできません。インスタンスコンストラクタでこれを行い、classが自己参照型でない場合は例外をスローするとどうなりますか? – Evk

+0

インスタンスコンストラクタではなく静的コンストラクタで行う必要がある理由を説明できますか? –

答えて

0

私を助けて。

R Foo<A>(A a) where A : Message<A> 
{ 
    // … 
} 

タイプリフレクションを使用すると、プログラムが有効かどうかは実行時にのみ認識されます。コンパイラがチェックできるソリューションを目指してください。

+0

私の記事のアップデートを読んでください。 実行時に実行しなければならないので、静的コンストラクターにチェックを入れます(条件が満たされないと例外が発生します)。ただし、パフォーマンス上の理由からインスタンスコンストラクターで実行できません。その静的コンストラクタafaikは現在のクラス型を公開していません。これは代替アプローチを探しています。 –

+0

@FabioAngela '[MyAttribute(MyMessages.Ping)]属性が適切な理由を理解できません。私が示唆しているのは、静的コンストラクタやランタイムチェックを必要としないことです。たぶんそれはあなたの問題に合っていませんが、私は今問題が何であるか分かりません。 – erisco

0

ベースクラスの静的コンストラクタは、ベースクラスに初めてアクセスされたときに呼び出されます。これは、派生クラスのインスタンス化である必要はありません。静的メソッドが基本クラスで呼び出されたとき。派生クラスは基本クラスの静的コンストラクタとはまったく関係ありません。同じクラスの基本クラスから複数のクラスを派生させることはできません。

派生クラスのインスタンス化は、あなたが扱っている派生クラスを基底クラスが知ることができる最も早い時刻です。非静的な基本クラスのコンストラクタ(if (!typeof(T).IsAssignableFrom(this.GetType())) throw new InvalidOperationException();)でオブジェクトの実行時の型をテストできます。欠点はもちろん、コンパイル時には捕まえられないということです。

+0

私の記事の更新を読んでください。私はインスタンスメソッドでそれを実行することはできませんし、静的コンストラクタは、ジェネリッククラスでは、すべての異なるTのために1回呼び出されています(そして、私はすでに私のdesingでそれを利用しています) –

+0

ベースクラスの静的コンストラクタが呼び出されますすべての 'T'は、すべての派生クラスに対してではありません。私。複数のクラスが同じ 'Base 'から派生した場合には1回だけ実行されます。リフレクションを使用してそれらを見つけることはできますが、基本クラスの静的コンストラクタで使用できる派生クラスはありません。 –

関連する問題