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;
}

如您所见,它存储了一个对象的两个副本(NewStateOldState)。我用它来比较字段变化。

我现在正试图让它工作,我得到一个跨多个对象的更改列表,然后将几种不同类型的 T 列表连接到一个这样的数组中(注意:两者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. ItemChange可以声明When属性。然后很容易将列表内容转换ItemChange为 concat 和 order by 的基础。

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

您尝试做的事情是不安全的,因为 anItemChange<Object1>和 an之间没有转换ItemChange<Object2>,当然也没有转换为任意ItemChange<T>的 。您可以尝试做的最好的事情是ItemChange<MyBase>,但类在 C# 中不是协变的,因此这是无效的:

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

因此,您不能将 anIEnumerable<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; }
}

然后,您可以将您的GetChangesGetChangeHistory方法更改为:

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 回答
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 回答
0

如果您定义了一个接口,该接口IReadableItemChange<out T>暴露了类型的只读属性T而不是该类型的字段,并且如果ItemChange<T>实现IReadableItemChange<T>了 ,那么ItemChange<Derived1>ItemChange<Derived2>都会实现IReadableItemChange<MyBase>(顺便说一下,IReadableItemChange<baseType>对于任何baseType这样的Derived1:baseTypeDerived2:baseType)。ItemChange<T>拥有一个接受IReadableItemChange<T>并从中复制数据的构造函数也可能会有所帮助。

于 2012-11-12T17:55:46.063 回答