重複の可能性:
ジェネリック拡張メソッドによる型推論なし
私は汎用インターフェースとそれの2つの具体的な実装を持っています。
次に、そのインターフェイスを実装するオブジェクトのコレクションの拡張メソッドであるメソッドがあります。このメソッドは、コレクションを処理し、処理されたコレクションを返すことになっています。
処理操作によってオブジェクトが変更されたり、新しいオブジェクトが生成されたりすることはないため、そのメソッドからの出力を入力と同じタイプにする必要があります。
つまり、メソッドからの出力を、渡した実際の具象型ではなく、インターフェイス型のコレクションにしたくありません。
ただし、これにより、メソッドを呼び出すときに型推論で問題が発生します。
LINQPadの例で説明します。
void Main()
{
var intervals = new Interval<int>[]
{
new Interval<int>(),
new Interval<int>(),
};
var ordered1 = intervals.Process(); // error 1
// var ordered2 = Extensions.Process(intervals); // error 2
}
public static class Extensions
{
public static IEnumerable<TInterval> Process<TInterval, T>(
this IEnumerable<TInterval> intervals)
where TInterval : IInterval<T>
{
return intervals;
}
}
public interface IInterval<T> { }
public class Interval<T> : IInterval<T> { }
これにより、次の2つのコンパイル時エラーが発生します。2つのメッセージを誘発するには、関連する行でコメントアウトする必要があります。
エラー1:
「Interval <int> []」に「Process」の定義が含まれておらず、「Interval <int> []」タイプの最初の引数を受け入れる拡張メソッド「Process」が見つかりませんでした(F4キーを押してディレクティブまたはアセンブリ参照を使用)エラー2:
メソッド'Extensions.Process <TInterval、T>(System.Collections.Generic.IEnumerable <TInterval>)'の型引数を使用法から推測できません。タイプ引数を明示的に指定してみてください。
その理由は、拡張メソッドが適合するかどうかを分析するときに、コンパイラが「十分に深く」見えていないためだと思います。
拡張方法を次のように変更した場合:
public static IEnumerable<IInterval<T>> Process<T>(
this IEnumerable<IInterval<T>> intervals)
{
return intervals;
}
次にコンパイルしますが、出力は次のようになります。
IEnumerable<IInterval<T>> result = ...
ではなく:
IEnumerable<Interval<int>> result = ...
もちろん、呼び出すときにタイプを指定すると、次のようになります。
var ordered = intervals.Process<IInterval<int>, int>();
...それで動作しますが、それだけではありません(IMO)。コンパイラーをだまして型を推測させる方法はありますか?
基本的に、私はしたい:
- 結果がインターフェースに入力される代わりに、メソッドを呼び出したタイプを取得します
- はい、これは確かにこれらの型を使用した別の呼び出しであるとコンパイラに伝え続ける必要はありません。これは、メソッドがLINQのような呼び出しチェーンの一部になるため、呼び出しごとに既知の型にキャストバックするか、呼び出しごとに完全な型を指定する必要があるためです。