0

私の状況はこれです。複数の異なるタイプのオブジェクトに対していくつかの検証とメッセージタイプのコードを実行する必要がありますが、クリーンさ (およびコードの再利用) のために、オブジェクトに関係なく、この検証へのすべての呼び出しが基本的に同じに見えるようにしたいと考えています。オーバーロードによってこれを解決しようとしていますが、ジェネリック コレクション オブジェクトに到達するまで問題なく動作します。

次の例は、ここで話していることを明確にする必要があります。

private string DoStuff(string tmp) { ... }

private ObjectA DoStuff(ObjectA tmp) { ... }

private ObjectB DoStuff(ObjectB tmp) { ... }

...

private Collection<ObjectA> DoStuff(Collection<ObjectA> tmp) {
    foreach (ObjectA obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj);
    if (tmp.Count == 0) return null;
    return tmp;
}

private Collection<Object> DoStuff(Collection<ObjectB> tmp) {
    foreach (ObjectB obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj);
    if (tmp.Count == 0) return null;
    return tmp;
}

...

Collection<T>異なるタイプごとにまったく同じコードを複製する必要があるため、これは本当に無駄のように思えます。それぞれに個別のインスタンスを作成するのではなく、DoStuffany を処理する単一のインスタンスを作成したいと思います。Collection<T>

を使用してみICollectionましたが、これには 2 つの問題があります。1 つ目は、メソッドをICollection公開していないことと、リスト内のオブジェクトの型がわからないため、ループを記述できないことです。を受け入れるメソッドがないため、 のようなより一般的なものを使用しても機能しません。実際のオブジェクトに適切なメソッドを呼び出す必要があります。適切なメソッドを選択し、適切にキャストするために if ステートメントのある種の巨大なリストを取得して実行するメソッドを作成すると、冗長なコードを取り除くという考え全体が無効になります。これらのメソッドをすべてコピーして貼り付けるだけでもかまいません。.RemoveforeachobjectDoStuffobjectDoStuffobjectCollection<T>

一般的な方法を使用してみましたが、これにはループDoStuff<T>で同じ問題があります。foreach設計時にはオブジェクトの型がわからないため、コンパイラは を呼び出させませんDoStuff(obj)

技術的には、コンパイラはコンパイル時にどの呼び出しを行う必要があるかを判断できる必要があります。これらはすべてプライベート メソッドであり、呼び出しで渡されるオブジェクトの特定の型は、メソッドが呼び出された時点ですべてわかっているためです。その知識は、このメソッドによって呼び出された後のメソッドには反映されていないようです。

ここではリフレクションを使用したくありません。すべてのCollection<T>メソッドをコピーして貼り付けるよりもコードがさらに複雑になり、パフォーマンスが低下するからです。何か案は?

---編集 1--- 山かっこの html コードを使用していなかったため、ジェネリック メソッド参照が正しく表示されていないことに気付きました。これは今すぐ修正する必要があります。

---編集 2--- 以下の応答に基づいて、Collection<T>メソッドを次のように変更しました。

private Collection<T> DoStuff<T>(Collection<T> tmp) {
    for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.RemoveAt(i);
    if (tmp.Count == 0) return null;
    return tmp;
}

ただし、これはまだ機能しません。コンパイラは、 を呼び出すときにどのオーバーロードされたメソッドを呼び出すかを判断できないためDoStuff(tmp[i])です。

4

2 に答える 2

-1

このようなもの?:

private Collection DoStuff<T>(Collection tmp) 
{
    // This will probably assert as you are modifying a collection while looping in it.
    foreach (T obj in tmp) if (DoStuff(obj) == null) tmp.Remove(obj); 
    if (tmp.Count == 0) return null;
    return tmp;
}

ここで、T はコレクション内のオブジェクトの型です。

主張する可能性が最も高い行があることに注意してください。それで:

private Collection DoStuff<T>(Collection tmp) 
{
    // foreach doesn't work if you are modifying the collection.
    // Looping backward with an index, so we never encounter an invalid index.
    for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.Remove(tmp[i]);
    if (tmp.Count == 0) return null;
    return tmp;
}

しかし、この時点で... T をもう使用していないのに、なぜジェネリックにするのでしょうか?

private Collection DoStuff(Collection tmp) 
{
    // DoStuff can be generic, but you shouldn't need to explicitly pass it a type...
    for (int i = tmp.Count - 1; i >= 0; i--) if (DoStuff(tmp[i]) == null) tmp.Remove(tmp[i]);
    if (tmp.Count == 0) return null;
    return tmp;
}
于 2012-10-25T21:30:29.497 に答える