10

ジェネリッククラスで次のオーバーロードされたメソッドを含むコードを使用しています。

public class A<T>
{
    public void Process(T item) { /*impl*/ }
    public void Process(string item) { /*impl*/ }
}

クラスをstringパラメーター化すると、ジェネリックパラメーターを使用してバージョンを呼び出すことができなくなりますか?

var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
4

4 に答える 4

14

特定のタイプは、一般的なタイプよりも優先されます。

たとえば、これは私がLINQPadでテストしたものです。

void Main()
{
    new A<string>().Process("Hello");
}

public class A<T>
{
    public void Process(T item) { Console.WriteLine("T"); }
    public void Process(string item) { Console.WriteLine("string"); }
}

// Output: string

ジェネリックメソッドの非表示に問題がある場合は、何かを再考する必要があります。ジェネリックメソッドを特定の型でオーバーロードすることで、「必要に応じてジェネリックオーバーロードを使用しますが、可能であれば、特定のバージョンを使用します。これは、何が最適かを認識している必要があるためです。

于 2012-05-30T20:20:05.140 に答える
5

はい。これは、C#仕様のセクション7.5.3の過負荷解決に記載されています。

7.5.3.6から:

「宣言された署名は一意である必要がありますが、型引数を置き換えると同じ署名になる可能性があります。そのような場合、上記の過負荷解決のタイブレークルールによって最も具体的なメンバーが選択されます。」

そこに示されている例では、以下の場合、の過負荷解決はG<int>.F1非ジェネリックを選択すると述べています

class G1<U>
{
    int F1(U u);
    int F1(int i);
}

ここで適用されるタイブレークルールは、7.5.3.2「より良い関数メンバー」で概説されています。

パラメータタイプシーケンス{P1、P2、…、PN}と{Q1、Q2、…、QN}が同等である場合(つまり、各Piが対応するQiへのID変換を持っている場合)、次のタイブレークルールが適用されます。より良い関数メンバーを決定するために。

  • MPが非ジェネリックメソッドであり、MQがジェネリックメソッドである場合、MPはMQよりも優れています。
于 2012-05-30T20:26:25.523 に答える
5

私が発見した方法は1つありますが、それは少し斜視です。ジェネリックスとオーバーロードはビルド時に解決されるため、ジェネリックメソッドを定義できます。

public static CallerClass
{
    public static CallGenericOverload<T>(GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val); 
    }   

    //We can also make an extension method. 
    //We don't have to of course, it's just more comfortable this way.
    public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val);
    }

}

public GenericClass<T>
{
     public string ProblemOverload(T val)
     {
         return "ProblemOverload(T val)";
     }
     public string ProblemOverload(string val)
     {
         return "ProblemOverload(string val)";
     }
}

ここで、次のことを行うと、次のようになります。

var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)

ジェネリックメソッドの代わりにジェネリッククラスを定義する場合は、同様のトリックを使用できます。重要なことは、転送先のパラメーターは、呼び出しでタイプするのではなく、タイプでProblemOverloadある必要があるということです。結局のところ、メソッドはビルド時に取得していることを認識しているため、パラメーターを受け入れるオーバーロードにバインドします。実行時に実際に取得するかどうかは関係ありません。TstringCallGenericOverloadTstring

于 2012-05-30T20:26:34.697 に答える
0

以前にこれを行ったことがあるので、私は「いいえ」と言う傾向がありますが、そうでないと主張する知識豊富な人々が常にいます。

メモリが機能する場合、ランタイムコンパイラは最も強く型付けされたオーバーロードを選択して実行します。

明確化

私の答えはひどい言い回しであり、私は反対票を投じるに値します。

OPは、「文字列のクラスをパラメーター化するときに、ジェネリックパラメーターを使用してバージョンを呼び出す可能性を失いますか?」と尋ねました。「いいえ、できません」ではなく、「いいえ、できません」と答えました。ジェネリックパラメータを使用してバージョンを呼び出す機能が失われます。」

もっと明確にすべきだった。

于 2012-05-30T20:22:19.443 に答える