5

基本的に、次のシナリオがあります。

public abstract class FooBase<T> where T : FooBase<T>
{
    public bool IsSpecial { get; private set; }

    public static T GetSpecialInstance()
    {
        return new T() { IsSpecial = true };
    }
}

public sealed class ConcreteFooA : FooBase<ConcreteFooA> { ... }
public sealed class ConcreteFooB : FooBase<ConcreteFooB> { ... }

しかし、ここで私が目にする問題はConcreteFooB : FooBase<ConcreteFooA> { ... }、実行時にクラスを完全に台無しにする可能性があることです (達成しようとしているロジックを満たしていません) が、それでも正しくコンパイルされます。

派生クラスが何であれ、ジェネリック T を強制するために私が考えていなかった方法はありますか?


更新:クラスで汎用パラメーター T を使用するFooBase<T>ことになります。それを out および in パラメーターとして持つすべてのメソッドをリストしたわけではありませんが、T の使用はあります。

4

5 に答える 5

3

あなたの質問に答えるには:

いいえ、これを強制するコンパイル時の解決策はありません。

于 2013-05-14T13:03:43.227 に答える
1

私の知る限り、これを強制するコンパイル時の方法はありません。ただし、実行時チェックを使用して強制することはできます。通常、異常なユーザー アクションはこれを引き起こすことはありません (コーディングが正しくないだけDebug.Assertです)。例えば

public abstract class FooBase<T> where T : FooBase<T>
{
    protected FooBase()
    {
        Debug.Assert(this.GetType() == typeof(T));
    }
}
于 2013-05-14T13:16:03.500 に答える
1

このルールを適用するには、次の 2 つの方法があります。

  1. 単体テスト - 単体テスト (または単体テスト) を作成して、コンパイルされた型がジェネリック パラメーターとして自身を渡していることを確認できます。
  2. コード分​​析 - これを強制するカスタム コード分析ルールを作成し、そのルールをエラー (対警告) として設定できます。これはコンパイル時にチェックされます。
  3. FxCop ルール - コード分析のサポートが組み込まれているバージョンの Visual Studio がない場合を除いて、コード分析ルールと同様に、代わりに FxCop を使用できます。

もちろん、これらのルールは標準のコンパイルでは適用されませんが、代わりに追加のツール (単体テスト、コード分析、FxCop) が必要です。誰かがあなたのコードを取得し、これらのツールを使用せずにコンパイルした場合、同じ問題が発生します... もちろん、その時点で、他の誰かが単体テストやコード分析/FxCop ルールを実行せずにコードをコンパイルするのはなぜですか?


または、これはお勧めしませんが、実行時エラーをスローすることもできます。なぜだめですか?マイクロソフトによると:

静的コンストラクターが例外をスローした場合、ランタイムはそれを 2 回目に呼び出すことはなく、プログラムが実行されているアプリケーション ドメインの有効期間中、型は初期化されないままになります。

それは本当にあなたの問題を解決しません。その上、静的初期化中に例外をスローすると、コード分析CA1065:DoNotRaiseExceptionsInUnexpectedLocationsに違反します。ですから、これを行うと、間違った方向に進んでしまいます。

于 2013-05-14T13:12:21.277 に答える
0

なぜこれを要件としているのかわからない。最初に、オブジェクト モデルに戻って、この要件が必要だと感じる理由を判断し、達成しようとしているものを達成するためのより良い方法があるかどうかを判断することをお勧めします。

上記のものには1つの問題があると思います.クラスの定義/宣言にジェネリックパラメーターがありませConcreteFooAConcreteFooB.

IFooBaseインターフェイスを作成し、具体的な実装でインターフェイスを実装する方が良いようです。を操作するすべてのインスタンスでIFooBase、 type の変数を使用しますIFooBase

そう:

public interface IFooBase { /* Interface contract... */ }

public class ConcreteFooA : IFooBase { /* Implement interface contract */ }
public class ConcreteFooB : IFooBase { /* Implement interface contract */ }

// Some class that acts on IFooBases
public class ActionClass
{
    public ActionClass(IFooBase fooBase) { this._fooBase = foobase };

    public DoSomething() { /* Do something useful with the FooBase */ }

    // Or, you could use method injection on static methods...
    public static void DoSomething(IFooBase fooBase) { /* Do some stuff... */ }
}

ほんのいくつかのアイデア。しかし、ジェネリックだけでやりたいことが実現できるとは思えません。

于 2013-05-14T13:06:09.947 に答える