2

ジェネリックメソッドを作成したい:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)

コードにはList<T>、、、、などの多くの変数があります。このメソッドには、列挙できない値をとるオーバーロードもあります。タイプパラメータ制約で特定のクラス(など)を禁止することは可能ですか?IEnumerable<T>xxxCollectionT[]string

私はすでに次のような1つのオーバーロードを作成しました:

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, object value)

このオーバーロードは、個々の値を処理するのに適していますが、値のコレクションを処理するには、わずかに異なる実装が必要です。ただし、コンパイラに除外するように指示できない限り、すべての文字列変数が間違ったオーバーロードに送信されるようにstring実装します。IEnumerable

4

4 に答える 4

3

いいえ。汎用タイプのパラメーター制約は、負の制約ではなく、の制約​​のみを適用できます。

実行時の型チェックは、おそらく次の方法です。

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
{
    if (typeof(T) == typeof(string))
    {
        throw new IllegalOperationException(...);
    }
}

メソッドに渡すすべての型が同じ基本クラスから継承する場合、または同じインターフェイスを実装する場合は、jrummellの単一制約の提案を使用して継承を強制できます。

はるかにエレガントではありませんが、異種タイプをサポートする場合にこれを行う別の方法は、特定のユースケースを処理するのに十分なオーバーロードを提供することです。

// supports int, float, DateTime, etc.
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<int> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<float> value)
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<DateTime> value)

// supports implementations of MyInterface
MvcHtmlString MyMethod(this HtmlHelper html, string title, IEnumerable<IMyInterface> value)

MyMethod<string>上記の例では、提供されている型の制約のいずれも満たさないため、呼び出すことはできません。ただし、タイプ制約はメソッドシグネチャの一部ではないため、これには使用できないことに注意してください。

于 2013-03-25T17:55:27.450 に答える
2

この拡張機能をモデルタイプにのみ使用する場合は、モデル基本クラスを作成し、Tそれを実装するタイプに制限することができます。

MvcHtmlString MyMethod<T>(this HtmlHelper html, string title, IEnumerable<T> value)
    where T : ModelBase
于 2013-03-25T17:54:57.607 に答える
2

これに制約を使用することはできず、を処理する意図を考慮すると、制約は必要ありませんstring

タイプを受け入れる既存のメソッドを考えると、タイプobjectの引数は、よりも一致するstringため、提案された新しいオーバーロードになります。ただし、過負荷になるという考えを放棄する必要はありません。また、実行時チェックに頼る必要もありません。の追加のオーバーロードを作成するだけです。コンパイラにとってシナリオをさらに簡単にすることで、との間の決定全体を回避します。IEnumerable<char>objectstringobjectIEnumerable<T>

与えられた

void Foo(object argument)
{
    Console.WriteLine("object");
}

void Foo<T>(IEnumerable<T> argument)
{
    Console.WriteLine("enumerable T");
}

void Foo(string argument)
{
    Console.WriteLine("string");
}

のメソッド呼び出しリスト

Foo("hello");
Foo(1);
Foo(new int[] { 1 });

出力を生成します

string
object
enumerable T

次に、文字列を1か所でオブジェクトのオーバーロードに強制変換できます。

void Foo(string argument)
{
    // Console.WriteLine("string");
    Foo((object)argument);
}
于 2013-03-25T18:25:13.183 に答える
1

残念だけど違う。

次のタイプの制約のみを指定できます。

where T : struct               // T must be a value type
where T : class                // T must be a reference type
where T : new()                // T must have a parameterless constructor
where T : <base class name>    // T must inherit from <base class>
where T : <interface name>     // T must implement <interface>
where T : U                    // T must inherit from U, where U is another
                               // generic parameter

参照:型パラメーターの制約

これで、これらの一部を使用して、タイプを制限することはできますが、タイプをロックアウトすることはできず、インターフェイス実装の制約など、許可するタイプを指定することしかできません。

インターフェイスまたは基本クラスの制約を使用して、「許可するタイプはすべて次の特性を持っている必要があります」と具体的に言うことができます。これがあなたの最良の選択肢だと思います。

ジェネリックがここで正しいツールであると確信していますか?

于 2013-03-25T17:56:02.097 に答える