21

等価性をサポートするすべての型で機能する、制約のないジェネリック メソッドがあるとします。ペア単位の等価性チェックを実行するため、O(n 2 )で機能します。

public static int CountDuplicates<T>(IList<T> list) 
{
    /* ... */ 
}

また、並べ替えをサポートする型でのみ機能する制約付きジェネリック メソッドもあります。O(n log n)でリストを並べ替えることから開始し、1 回のパスですべての重複をカウントします。

public static int CountDuplicatesFast<T>(IList<T> list) 
    where T : IComparable<T> 
{
    /* ... */ 
}

そのため、リストの要素の型が順序付けをサポートしていることが静的にわかっている場合、呼び出し元は高速メソッドを呼び出すことを選択できます。IList<T>T が制約されていない場合、呼び出し元自体がジェネリックで動作する可能性があるため、最初の (遅い) メソッドを呼び出す唯一のオプションです。

Tここで、型が実際にインターフェイスを実装しているかどうかを実行時に最初のメソッドでチェックし、実装しているIComparable<T>場合は高速メソッドを呼び出します。

public static int CountDuplicates<T>(IList<T> list)
{
    if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
    {
        return CountDuplicatesFast(list);
    }
    else
    {
        /* use the slow algorithm */
    }
}

問題は、コンパイラが呼び出しを拒否することですCountDuplicatesFast(list):

エラー CS0314: 型 'T' は、ジェネリック型またはメソッド 'Program.CountDuplicatesFast<T>(System.Collections.Generic.IList<T>)' で型パラメーター 'T' として使用できません。'T' から 'System.IComparable<T>' へのボックス変換や型パラメーターの変換はありません。

私が何をしているのかを知っていることを信頼し、制約チェックをスキップするようにコンパイラーを説得することは可能ですか?

4

2 に答える 2

8

ヘルパー クラスとdynamic型を使用して、コンパイル時のチェックをスキップできます。

sealed class CountDuplicatesFastCaller
{
    public int Call<T>(IList<T> list) where T : IComparable<T>
    {
        return CountDuplicatesFast(list);
    }
}

public static int CountDuplicates<T>(IList<T> list)
{
    if (typeof (IComparable<T>).IsAssignableFrom(typeof (T)))
    {
        return ((dynamic) new CountDuplicatesFastCaller()).Call(list);
    }
    else
    {
        /* use the slow algorithm */
    }
}

これは、DLR キャッシュ メカニズムにより、純粋なリフレクションよりも高速になるはずです。

于 2013-05-06T19:31:50.473 に答える
7

を使用してそれを行う方法は次のdynamicとおりです。

if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
    return CountDuplicatesFast((dynamic)list);
}

またはリフレクションで:

if (typeof(IComparable<T>).IsAssignableFrom(typeof(T)))
{
    var method = typeof(MyType).GetMethod("CountDuplicatesFast");
    var generic = method.MakeGenericMethod(typeof(T));
    return (int)generic.Invoke(null, new object[] { list });
}

これを静的に(つまり、リフレクションや なしで)行う方法はないと思いますdynamic

于 2013-05-06T19:32:10.390 に答える