編集:
与えられた回答から、以下で質問している設計を実際にどのように実装する必要があるかがかなり明確になりました。これらの提案を念頭に置いて (そして、私のコード例はコンパイルすらしないことを丁寧に指摘するコメントに応えて)、一般的なコンセンサスを反映するように次のコードを編集しました。残っている質問は、コードを考えるともはや意味をなさないかもしれませんが、後世のためにそのままにしておきます。
次のような関数の 3 つのオーバーロードがあるとしIEnumerable<T>
ます。ICollection<T>
IList<T>
public static T GetMiddle<T>(IEnumerable<T> values) {
IList<T> list = values as IList<T>;
if (list != null) return GetMiddle(list);
int count = GetCount<T>(values);
T middle = default(T);
int index = 0;
foreach (T value in values) {
if (index++ >= count / 2) {
middle = value;
break;
}
}
return middle;
}
private static T GetMiddle<T>(IList<T> values) {
int middleIndex = values.Count / 2;
return values[middleIndex];
}
private static int GetCount<T>(IEnumerable<T> values) {
// if values is actually an ICollection<T> (e.g., List<T>),
// we can get the count quite cheaply
ICollection<T> genericCollection = values as ICollection<T>;
if (genericCollection != null) return genericCollection.Count;
// same for ICollection (e.g., Queue<T>, Stack<T>)
ICollection collection = values as ICollection;
if (collection != null) return collection.Count;
// otherwise, we've got to count values ourselves
int count = 0;
foreach (T value in values) count++;
return count;
}
ここでの考え方は、 を持っていればIList<T>
仕事が楽になるということです。一方、または;ICollection<T>
でさえも仕事をすることができます。IEnumerable<T>
これらのインターフェイスの実装は効率的ではありません。
これが機能するかどうかはわかりませんでしたが (ランタイムが渡されたパラメーターに基づいてオーバーロードを選択できる場合)、テストしたところ、機能するようです。
私の質問は次のとおりです。私が考えていなかったこのアプローチに問題はありますか? あるいは、これは実際には良いアプローチですが、それを達成するためのより良い方法があります (おそらく、values
引数をIList<T>
最初にキャストし、キャストが機能する場合はより効率的なオーバーロードを実行することによって)? 他の人の考えを知りたいだけです。