趣味のプロジェクトとして (そしてジェネリック/拡張メソッドに深く没頭するために)、パラメーター チェック ライブラリを作成しています!
パラメータを記述する Argument というモデルがあり、次のようになります。
public class Argument<T>
{
internal Argument(string name, T value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public T Value { get; private set; }
}
パラメーターの検証が開始されると、このオブジェクトのインスタンスが作成され、個々の検証は、それからぶら下がっている拡張メソッド (実際のロジックを含む) を呼び出すことによって実行されます。
このような拡張メソッドの 1 つは、コレクションに少なくとも 1 つの項目が含まれていることを確認します。現在は次のようになっています。
public static Argument<IEnumerable<T>> HasItems<T>(this Argument<IEnumerable<T>> argument)
{
if (!argument.Value.Any())
throw Error.Generic(argument.Name, "Collection contains no items.");
return argument;
}
しかし、うまくいかないようです。たとえば、この単体テストを書くとしたら、次のようになります。
[TestMethod]
public void TestMethod1()
{
var argument = new List<int>() { 1, 2, 6, 3, -1, 5, 0 };
Validate.Argument("argument", argument)
.IsNotNull()
.HasItems()
.All(v => v.IsGreaterThan(0));
}
HasItems が Intellisenseに表示されず、次のコンパイル エラーが発生します。
'Validation.Argument<System.Collections.Generic.List<int>>'
'HasItems' の定義が含まれておらず、タイプの最初の引数を受け入れる拡張メソッド 'HasItems''Validation.Argument<System.Collections.Generic.List<int>>'
が見つかりませんでした (using ディレクティブまたはアセンブリ参照がありませんか?)
そして、値を拡張メソッドに直接渡そうとすると、次のようになります。
CollectionTypeExtensions.HasItems(Validate.Argument("argument", argument));
私はこれを得る:
の最適なオーバーロードされたメソッド マッチに
'Validation.CollectionTypeExtensions.HasItems<int>(Validation.Argument<System.Collections.Generic.IEnumerable<int>>)'
は無効な引数があります
私の調査に基づいて、これが機能するために必要なものは「分散」と呼ばれ、インターフェイスとデリゲートに適用されますが、クラスには適用されません (つまり、すべてのクラスは不変です)。
つまり、別の方法で機能する可能性があります。頭に浮かぶのは、次のように T に直行するように書き直すことです。
public static Argument<T> HasItems<T, TElement>(this Argument<T> argument)
where T : IEnumerable<TElement>
{
if (!argument.Value.Any())
throw Error.Generic(argument.Name, "Collection contains no items.");
return argument;
}
..しかし、メソッドが呼び出されるときに TElement を明示的に指定する必要があるため、それも機能しません。型制約で非ジェネリック IEnumerable インターフェイスを使用するようにフォールバックすることもできますが、その場合、IEnumerable を IEnumerable に強制する方法を見つける必要があります (これには、T がそのコンテキストにあることを知る必要があります)、または複製する必要があります。アイテムの存在をテストするための Any() の機能と、非常に面倒な別の拡張メソッド (All) があるため、むしろ避けたいと思います。
最終的に、私の質問は次のとおりだと思います:拡張メソッドを適切にアタッチするにはどうすればよいですか?