1

私は、私たちが使用する重要な内部テスト ツールで使用されるファイルのエディターに取り組んでいます。ツール自体は大きくて複雑で、リファクタリングや書き直しには、当面の間、それに専念できる以上のリソースが必要になるため、大きな変更になると私の手は縛られます。.NET 言語を使用する必要があります。

ファイルは、ツールで使用される 4 つのクラスの XML シリアル化バージョンです (これらを A、B、C、および D と呼びましょう)。すべてが順調な場合、クラスはツリー構造を形成します。私たちのエディターは、一連のファイルをロードし、それらをデシリアライズし、それらの間の関係を解決し、見つけた悪い状態を追跡することによって機能します。これらのファイルを手動で編集すると、大量のエラーが発生します。

特定の種類のエラーについて、問題のあるすべてのファイルのコレクションを維持したいと考えています。4 つのクラスすべてで問題が発生する可能性があるため、コードの重複をできるだけ減らしたいと考えています。重要な要件は、ユーザーがアイテムをセットで取得できる必要があることです。たとえば、エラーのあるすべての A オブジェクトを取得する必要があり、コレクション全体を反復処理して必要なものを選択するように指示することは、GetAs()メソッドと比較して受け入れられません。したがって、最初に考えたのは、シリアル化解除されたオブジェクトといくつかのメタデータを関連付けてエラーを示す汎用アイテムを作成することでした。

public class ErrorItem<T>
{
    public T Item { get; set; }
    public Metadata Metadata { get; set; }
}

次に、ユーザーが必要とするときに特定のクラスのアイテムを抽出するヘルパー メソッドを使用して、すべてのエラー アイテムを保持できるコレクション クラスを作成します。ここからトラブルが始まります。

共通の祖先から継承するクラスはありません ( を除くObject)。これはおそらく初期設計の間違いでしたが、数日かけて考えてみたところ、各項目を一意に識別する GUID プロパティ以外にクラスに共通点があまりないため、元の設計者が継承によってそれらを関連付けませんでした。これは、統合されたエラー コレクションがErrorItem<Object>オブジェクトを格納する必要があることを意味します。これは、入ってくるものを制限する基本クラスやインターフェイスがないためです。

Public Class ErrorCollection
{
    public ErrorItem<Object> AllItems { get; set; }
}

ただし、これはパブリック インターフェイスに影響を与えます。私が本当に欲しいのは、次のErrorItemような適切なジェネリック型を返すことです:

public ErrorItem<A>[] GetA()

収納しかできないから無理ErrorItem<Object>!頭の中でいくつかの回避策を検討しました。ほとんどの場合ErrorItem、適切なタイプの新しいものをオンザフライで作成することが含まれますが、それはちょっと醜いように感じます. 別の考えでは、Dictionaryアイテムをタイプ別に整理するために を使用していましたが、まだ正しくないようです。

ここで私を助けるかもしれないある種のパターンはありますか? これを解決する最も簡単な方法は、A、B、C、および D が派生する基本クラスを追加することだとわかっていますが、元のツールへの影響をできるだけ小さくしようとしています。回避策のコストは、最初のツールを変更するためにプッシュする必要があるほど大きいですか?

4

3 に答える 3

1

これはあなたが探しているものですか?

private List<ErrorItem<object>> _allObjects = new List<ErrorItem<object>>();

public IEnumerable<ErrorItem<A>> ItemsOfA
{
    get
    {
        foreach (ErrorItem<object> obj in _allObjects)
        {
            if (obj.Item is A)
                yield return new ErrorItem<A>((A)obj.Item, obj.MetaData);
        }
    }
}

をキャッシュしたい場合は、ItemsOfA簡単に行うことができます:

private List<ErrorItem<A>> _itemsOfA = null;

public IEnumerable<ErrorItem<A>> ItemsOfACached
{
    if (_itemsOfA == null)
        _itemsOfA = new List<ErrorItem<A>>(ItemsOfA);
    return _itemsOfA;
}
于 2008-09-10T14:57:36.077 に答える
1

これまでのところ、私が行っている答えは、フライガイボブとメンデルト・シーベンガからの答えを組み合わせたものです。

メンデルト・シーベンガが指摘したように、基本クラスを追加すると名前空間が汚染され、同様の問題が発生します。コレクションに入れることができるアイテムをより細かく制御できますが、ErrorItem<BaseClass>それでも保存していくつかのキャストを行う必要があるため、同じ根本原因で少し異なる問題が発生します。これが、私が投稿を答えとして選択した理由です。それは、何があってもいくつかのキャストを行う必要があることを指摘しており、KISS は追加の基本クラスとジェネリックが多すぎると指示します。

yield returnflyguybob の答えは、ソリューション自体ではなく、キャッシュされていないバージョンを簡単に記述できるようになることを思い出させてくれたのが好きです(LINQ を使用する予定でした)。キャッシュされたバージョンはもう少し賢明だと思いますが、予想されるパフォーマンスパラメータにより、キャッシュされていないバージョンが著しく遅くなることはありません.

于 2008-09-10T16:48:01.240 に答える
0

A、B、C、および D に共通点がない場合、基本クラスを追加しても実際には何も得られません。それは単なる空のクラスになり、実際にはオブジェクトと同じになります。

ジェネリックを使用せずに ErrorItem クラスを作成し、Item をオブジェクトにして、参照されるオブジェクトを使用する場合はキャストを行います。Guid 以外の A、B、C、または D クラスのプロパティまたはメソッドを使用する場合は、とにかくそれらをキャストする必要がありました。

于 2008-09-10T14:47:35.383 に答える