私は一般的な方法を持っています。ジェネリックメソッドで1つのタイプを制限したい。問題は許可されない派生型です-私はこれを望んでいません。コード例:
public static T Generate<T>(T input)
where T : Operation // ALLOWS BinaryOperation - NOT WANT THIS
{
//...
}
私が要求することをどのように行うのですか?
問題は、許可されない派生型です
実行時にチェックせずに、この制約を適用する方法はありません。そうすることは、どのタイプでも制限なしに派生型を渡すことができるようにする必要があると述べているリスコフの置換原則の違反になります。
これを強制する必要がある場合は、次のようなランタイムチェックでのみ機能します。
public static T Generate<T>(T input)
where T : Operation // ALLOWS BinaryOperation - NOT WANT THIS
{
// Checks to see if it is "Operation" (and not derived type)
if (input.GetType() != typeof(Operation))
{
// Handle bad case here...
}
// Alternatively, if you only want to not allow "BinaryOperation", you can do:
if (input is BinaryOperation)
{
// Handle "bad" case of a BinaryOperation passed in here...
}
}
この場合、同じコードが次のように機能するため、一般的なものにする理由は実際にはないことに注意してください。
public static Operation Generate(Operation input)
{ // ...
Operation
型が構造体でもシール クラスでもない場合のように、メソッドが 1 つの特定の型のみを受け入れるように強制することはできません。
とにかくこれが機能しない理由を例で示しましょう。
public void Generate<T>(Operation op)
// We assume that there is the keyword "force" to allow only Operation classes
// to be passed
where T : force Operation
{ ... }
public void DoSomething()
{
Generate(new BitOperation()); // Will not build
// "GetOperation" retrieves a Operation class, but at this point you dont
// know if its "Operation" or not
Operation op = GetOperation();
Generate(op); // Will pass
}
public Operation GetOperation() { return new BitOperation(); }
BitOperation
ご覧のとおり、制限があっても簡単に通過できます。
上記の他の解決策 ( struct、sealed ) 以外に、解決策は 1 つだけです:ランタイム チェック。 このための小さなヘルパー メソッドを自分で作成できます。
public class RuntimeHelper
{
public static void CheckType<T>(this Object @this)
{
if (typeof(T) != @this.GetType())
throw new ....;
}
}
public void Generate(Operation op)
{
op.CheckType<Operation>(); // Throws an error when BitOperation is passed
}
ヘルパーを高速化したい場合はRuntimeHelper<T>
、T 型の静的な読み取り専用型変数を持つジェネリック クラスを使用できます。
これを行うと、拡張メソッドを使用できなくなるため、呼び出しは次のようになります。
RuntimeHelper<Operation>.CheckType(op);