3

私は、コンパイル時の強力な型チェックに焦点を当てた流暢な引数アサーション ライブラリを実装しています。Intellisense は、アサートされた型で使用可能なメソッドと拡張機能のみを表示する必要があります。

IEnumerable の拡張機能を作成するときに、適切な型引数を解決できません。

ライブラリのアイデアは、IAssertion 型のアサーション インスタンスを返す任意の型で ThrowIf (または ThrowIfNot) を呼び出すことができるということです。

public static IAssertion<T> ThrowIf<T>(this T t)
{
    return new IfAssertion<T>(t);
}

IEnumerable に特定のアイテムが含まれているかどうかを確認したいと思います。2 つのオーバーロードがあり、1 つは型 T のオブジェクトをパラメーターとして受け取り、もう 1 つは評価を行う関数を受け取ります。

public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, T2 item)
    where T1 : IEnumerable<T2>
{
    // assertion logic
    return assertion.Value;
}

public static T1 Contains<T1, T2>(this IAssertion<T1> assertion, Func<T2, bool> func)
    where T1 : IEnumerable<T2>
{
    // assertion logic
    return assertion.Value;
}

実際の型のインスタンスを取るオーバーロードを使用すると、すべてがうまくいきます。ただし、関数コンパイラを使用した後者は、キャストが行われない限り、型引数を適切に推論できません。

var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // does not compile

関数パラメーターのキャストを行わずにコンパイラーを満足させる方法はありますか?

実装の詳細については、 https ://bitbucket.org/mikalkai/argument-assertions/overview を参照してください。

4

1 に答える 1

3

免責事項: この回答は、共変IAssertionにできる場合にのみ有効です。

それが共変であると仮定すると、必ずしも 2 つのジェネリック型パラメーターとメソッドがIAssertion必要になるわけではありません。代わりに、インターフェイスで直接指定し、次のようにジェネリック型パラメーターを 1 つだけ使用します。T1T2ContainsIEnumerable

public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, T item)
{
  // assertion logic
  return assertion.Value;
}

public static IEnumerable<T> Contains<T>(this IAssertion<IEnumerable<T>> assertion, Func<T, bool> func)
{
  // assertion logic
  return assertion.Value;
}

次に、次のように contains メソッドを使用できます。

var list = new List<string>();
list.ThrowIf().Contains("foo"); // compiles
list.ThrowIf().Contains((string s) => false); // compiles
list.ThrowIf().Contains(s => false); // compiles now too
于 2016-03-29T19:56:04.190 に答える