6

3D測定データの計算を実行するクラスライブラリを使用しています。これにより、次のメソッドが公開されます。

MeasurementResults Calculate(IList<IList<Measurement>> data)

(もちろん、Measurementの)リストのインデックス可能なリストでこのメソッドを呼び出すことを許可したいと思います。たとえば、次の両方です。

Measurement[][] array;
List<List<Measurement>> list;

配列を使用してメソッドを呼び出すと正常に機能しますが、これは少し奇妙です。ここで動作しているコンパイラのトリックはありますか?で電話をかけようとするとList、おなじみのエラーが発生します。

cannot convert from 'List<List<Measurement>>' to 'IList<IList<Measurement>>'

そこで、引数とメソッドの間で一般的な定義を分割し、必要に応じてIListタイプに変換するメソッドを使用して、ファサードクラス(他のものも含む)を作成しました。

MeasurementResults Calculate<T>(IList<T> data) where T : IList<Measurement>
{
  IList<IList<Measurement>> converted = data as IList<IList<Measurement>>;
  if(converted == null)
    converted = data.Select(o => o as IList<Measurement>).ToList();
  return Calculate(converted);
}

これは問題を解決するための良い方法ですか、それともより良いアイデアがありますか?

また、問題のさまざまな解決策をテストしているときに、クラスライブラリメソッドがIEnumerableの代わりにで宣言されている場合は、配列と:IListの両方を使用してメソッドを呼び出しても問題ないことがわかりました。List

MeasurementResults Calculate(IEnumerable<IEnumerable<Measurement>> data)

コンパイラのトリックが再び機能しているのではないかと思いますが、なぜ彼らがIList作業List中に動作しなかったのでしょうか。

4

3 に答える 3

6

で共変でIEnumerable<T>あるため、これをで実行しても問題ありません。「入力」と「出力」の両方に使用されるため、を使用してこれを行うのは安全ではありません。TIList<T>

特に、次のことを考慮してください。

List<List<Foo>> foo = new List<List<Foo>>();
List<IList<Foo>> bar = foo;
bar.Add(new Foo[5]); // Arrays implement IList<T>

// Eh?
List<Foo> firstList = foo[0];

ジェネリック共変性と反変性の詳細については、MSDNを参照してください。

于 2012-04-19T14:15:07.717 に答える
3

メソッドがあるとします

void Bar(IList<IList<int>> foo)

内で、にを追加することBarは完全に許容されるはずです-結局のところ、実装しますね?int[]fooint[]IList<int>

ただし、を使用して呼び出しBarた場合は、 !のみを受け入れるものList<List<int>>にを追加しようとします。これは悪いでしょう。したがって、コンパイラはこれを許可しません。int[]List<int>

また、問題のさまざまな解決策をテストしているときに、クラスライブラリメソッドがIEnumerableの代わりにで宣言されている場合は、配列と:IListの両方を使用してメソッドを呼び出しても問題ないことがわかりました。List

確かに、行動コントラクトが「sを出力 できる」とだけ言っているのであればint、何も問題はありません。さらなる研究の重要な用語は共変性変性であり、誰も*どちらがどちらであるかを思い出せません。

あなたの特定のケースでは、入力を読み取るCalculateだけの場合、それを消費するように変更することは絶対に正しいことです-それは両方ともあなたが任意の適格なオブジェクトを渡すことを可能にし、さらにこのメソッドが意図的に署名を読んでいる人に伝えます入力を変更するのではなく、消費するように設計されています。IEnumerable


*まあ、ほとんど誰も

于 2012-04-19T14:21:12.153 に答える
1

私が変更する実装にはいくつかのことがあります。まず第一に、元のオブジェクトがあった結果にnullを挿入する可能性があります。個人的には投げたほうがいいです。

MeasurementResults Calculate<T>(IList<T> data) where T : IList<Measurement>
{
    return Calculate(data as IList<IList<Measurement>>
                     ?? data.Cast<IList<Measurement>>().ToList());
}

短い例ですが、私が実際にメソッドを実装するかどうかは疑問ですが、あなたの場合に私が個人的に行うことと似ています。インターフェースはそのように書かれているので(私は願っています)、可能であればそれと戦うのではなく、その知識を私の実装で使用しようと思います。コード(またはそのようなもの)を使用する場合、メソッドでリストに加えられた変更は元のリストに反映されません。これはメソッドに渡される新しいリストであり、署名はIListを要求するため、変更を加えることができる可能性があります。

オブジェクトの代わりにnullがリストに含まれない可能性があることを除けば、基本的にはキャストメソッドを使用するように変更しました。これは、基本的には達成しようとしていることだからです。(キャストではカスタム変換演算子は使用できません)。

于 2012-04-19T14:23:09.197 に答える