0

ジェネリック パラメータを持つメソッドがあります。

internal void DoSomething<T>(T workWithThis)
{
}

ここで、指定したいいくつかのインターフェイスの 1 つを継承するパラメーターのみを受け入れるように、このメソッドを制限したいと考えています。しかし、私はまだその方法を見つけていません。私が欲しいものは次のようになります:

internal void DoSomething<T>(T workWithThis) where T : ISomething | ISomethingElse
{
}

明らかにこれは機能していないので、静的メソッドで T のタイプを確認してみました。

public static bool CheckType(Type t)
{
return */check here*/
}

internal void DoSomething<T>(T workWithThis) where T : CheckType(typeof(T))
{
}

明らかにこれもうまくいきません。問題はなぜですか?私の理解に基づいて、コンパイラがそれを妨げているのはなぜですか、それが機能しない理由はありません

4

4 に答える 4

5

私の理解に基づいて、コンパイラがそれを妨げているのはなぜですか、それが機能しない理由はありません

C# で言語としてサポートされていないことを実行しようとしているため、コンパイラが実行を妨げています。使用しようとしている構文は、C# 仕様のセクション 10.1.5 のプロダクションに準拠していません。

言語としての C# は、必要なシナリオをサポートしていません。

言語がこの種の柔軟性を許可しない理由については、次の通常のバランスをとる行為に帰着します。

  • これにより何人の開発者がどのくらい利益を得るか
  • より複雑な言語を理解するための他の開発者への余分な負担
  • 言語機能の設計、実装、およびテストに必要なリソース (主に Microsoft 内)

もちろん、これは C# だけではありません。CLR もそのような制限をサポートする必要があり、少なくとも他の CLR 言語もそれを理解するように促します。

2 つの別々の方法でこれを解決することをお勧めします。オーバーロードはジェネリック型の制約だけでは異なることができないため、ジェネリック メソッドのオーバーロードだけではないことに注意してください。インターフェイスを実装する値型のボックス化を気にしない場合は、次のようにオーバーロードできます。

internal void DoSomething(ISomething something)
{
}

internal void DoSomething(ISomethingElse somethingElse)
{
}

... ただし、式が両方のインターフェイスを実装する型である値を渡すと、オーバーロードのあいまいさが生じます。

または、2 つのメソッドに異なる名前を付けます。

于 2013-10-28T10:23:15.420 に答える
2

コンパイラは、コンパイル時にすべての制約を検証する必要があり、そのためにメソッドを呼び出すことはできません。

where制約で指定できるのは、次のものだけです。

  • new()- パラメーターなしのコンストラクターが必要
  • class- 参照型でなければなりません
  • struct- 値型でなければなりません
  • SomeBaseClass
  • ISomeInterface
  • T : U- 他の汎用パラメーターのいずれかである、継承する、または実装する必要があります

詳細については、「C# プログラミング ガイド - 型パラメーターの制約」を参照してください。

理由については、「これが機能する理由はないと思います」と答える必要はありません。「なぜこれが機能するのか」という反対の方向から始めて、実装する価値があるように、もっともらしく現実的なシナリオと要件を考え出す必要があります。Eric Gunnersonのマイナス 100 ポイントを参照してください。

コードでこれを修正するには、共通のインターフェイスから両方のインターフェイスを派生させ、代わりにそれに制約を追加する必要があります。

2 つのインターフェイスに共通点が何もない場合、最初に実際に制約を追加するメリットに疑問を感じます。

たとえば、コードがジェネリック型/メソッドで使用されているオブジェクトのメソッドを呼び出す場合、明らかに両方のインターフェイスがそのメソッドが何であるかについて同じ概念を持っている必要があり、それを行う唯一の方法は共通基本インターフェースで定義されるメソッド。2 つのインターフェイスがたまたま同じメソッドまたはプロパティを同じ署名で宣言していても、同じメソッドにはなりません。

そうは言っても、ここでジェネリックも必要ですか?

2 つのメソッドを宣言し、それぞれがそのようなインターフェイスを 1 つ取るのはどうですか?

internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)
于 2013-10-28T10:24:09.873 に答える
1

コンパイラはジェネリック制約を使用して、ジェネリック メソッド内の T で使用できる操作を決定します。そのため、 or 式を許可することはタイプ セーフではありません。たとえば、次の 2 つのインターフェイスがIFirstありISecondます。

public interface IFirst
{
    void First();
}

public interface ISecond
{
    void Second();
}
internal void DoSomething<T>(T workWithThis) where T : IFirst or ISecond
{
    //How to call this method if the type is ISecond
    workWithThis.First();
    //How to call this method if the type is IFirst
    workWithThis.Second();
}
于 2013-10-28T10:27:57.050 に答える
0

それらすべてを保持する空のインターフェースを定義できます。

C#インターフェイスは複数の継承を持つことができることに注意してください。

例えば:

public interface IHolder : ISomething, ISomethingElse 
{

}

およびジェネリックの場合

internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}
于 2013-10-28T10:23:58.037 に答える