4

ItemChange<T>次のようなクラスがあります。

public class ItemChange<T> where T : MyBase
{
    public DateTime When { get; set; }
    public string Who { get; set; }
    public T NewState;
    public T OldState;
}

ご覧のとおり、オブジェクトの2つのコピー(NewStateおよびOldState)が格納されています。これを使用して、フィールドの変更を比較します。

私は今、これを機能させようとしています。ここでは、複数のオブジェクトにわたる変更のリストを取得し、いくつかの異なるタイプのTリストを次のように1つの配列に連結します(注:両方Object1Object2派生MyBase

public IEnumerable<ItemChange<T>> GetChangeHistory<T>(int numberOfChanges) where T : MyBase
{
    IEnumerable<ItemChange<Object1>> obj1Changes= GetChanges<Object1>();
    IEnumerable<ItemChange<Object2>> obj1Changes= GetChanges<Object2>();
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberofChanges);
}

ご覧のとおり、複数のタイプからの変更を連結する必要がありますが、最新の変更数(で定義numberOfChanges)を取得したいと思います。

Concat行でコンパイラエラーが発生するため、以下を機能させる方法についての提案があります(これを機能させるには、特別な方法でキャストする必要があると思います)。

それを行う方法はありますか?

4

4 に答える 4

4

ItemChange<T>と呼ばれるに基本クラスを追加することをお勧めしItemChangeます。はItemChangeWhenプロパティを宣言できます。ItemChangeそうすれば、リストの内容をベースにキャストして、連結して並べ替えることが非常に簡単になります。

using System;
using System.Collections.Generic;
using System.Linq;

namespace brosell
{

public class MyBase
{

}

public class ItemChange
{
    public DateTime When { get; set; }

}

public class ItemChange<T>: ItemChange where T : MyBase
{
    public string Who { get; set; }
    public T NewState;
    public T OldState;
}

public class Sub1: MyBase
{

}

public class Sub2: MyBase
{

}

   public class HelloWorld
   {
    public static void Main(string[] args)
    {
        List<ItemChange<Sub1>> listOfSub1 = new List<ItemChange<Sub1>>();
        List<ItemChange<Sub2>> listOfSub2 = new List<ItemChange<Sub2>>();

        var concated = listOfSub1.Cast<ItemChange>().Concat(listOfSub2.Cast<ItemChange>());

        var filtered = concated.OrderByDescending(ic => ic.When).Take(10);  

        Console.WriteLine("{0}", filtered.Count());
        }
   } 
}
于 2012-11-11T14:51:46.460 に答える
1

これはどう?今はテストできないのでわかりません。

public IEnumerable<ItemChange<T>> GetChangeHistory<T>(int numberOfChanges) where T : MyBase
{
    IEnumerable<ItemChange<MyBase>> obj1Changes = GetChanges<Object1>().Select(i => new ItemChange<MyBase>(){ When = i.When, Who = i.Who, NewState = i.NewState, OldState = i.OldState });
    IEnumerable<ItemChange<MyBase>> obj1Changes = GetChanges<Object2>().Select(i => new ItemChange<MyBase>(){ When = i.When, Who = i.Who, NewState = i.NewState, OldState = i.OldState });
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberofChanges);
}

ItemChange<MyBase>fromItemChange<Object1>または。の新しいインスタンスを作成しますItemChange<Object2>

.ToList()使用法によっては、パフォーマンスを向上させるためにLinqの最後に追加することをお勧めします。

于 2012-11-11T14:16:18.293 に答える
1

ItemChange<Object1>との間には変換ItemChange<Object2>がなく、任意のに変換されないため、実行しようとしていることは安全ではありませんItemChange<T>。最善の方法はItemChange<MyBase>、C#ではクラスが共変ではないため、これは無効です。

ItemChange<MyBase> change = new ItemChange<Object1>();

IEnumerable<ItemChange<Object1>>したがって、をにキャストすることはできませんIEnumerable<ItemChange<Object2>>

ただし、ItemChange<T>クラスのインターフェースを作成すると、安全に作成できます。

public interface IItemChange<out T> where T : MyBase
{
    DateTime When { get; set; }
    string Who { get; set; }
    T NewState { get; }
    T OldState { get; }
}

public class ItemChange<T> : IItemChange<T> where T : MyBase
{
    public DateTime When { get; set; }
    public string Who { get; set; }
    public T NewState { get; set; }
    public T OldState { get; set; }
}

GetChanges次に、GetChangeHistoryメソッドを次のように変更できます。

private static IEnumerable<IItemChange<T>> GetChanges<T>() where T : MyBase { ... }

public static IEnumerable<IItemChange<MyBase>> GetChangeHistory(int numberOfChanges)
{
    IEnumerable<IItemChange<MyBase>> obj1Changes = GetChanges<Object1>();
    IEnumerable<IItemChange<MyBase>> obj2Changes = GetChanges<Object2>();
    return obj1Changes.Concat(obj2Changes).OrderByDescending(r => r.When).Take(numberOfChanges);
}
于 2012-11-11T14:39:27.377 に答える
0

そのタイプのフィールドではなく、そのタイプIReadableItemChange<out T>の読み取り専用プロパティを公開するインターフェイスを定義し、実装されている場合は、との両方が実装されます(そして、ちなみに、とのようなものについては)。を受け入れてそこからデータをコピーするコンストラクターがあると便利な場合もあります。TItemChange<T>IReadableItemChange<T>ItemChange<Derived1>ItemChange<Derived2>IReadableItemChange<MyBase>IReadableItemChange<baseType>baseTypeDerived1:baseTypeDerived2:baseTypeItemChange<T>IReadableItemChange<T>

于 2012-11-12T17:55:46.063 に答える