我有一个名为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;
}
如您所见,它存储了一个对象的副本(NewState
和OldState
)。我用它来比较字段变化。
我现在正试图让这个工作,我得到一个跨多个对象的更改列表,然后将几个不同类型的T列表连接成一个这样的数组(注意:Object1
和{{1从Object2
派生:
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);
}
定义)
关于如何让以下工作作为Concat行的任何建议都会给我一个编译器错误(我假设我必须采用一些特殊的方式来使其工作)。
有没有办法做到这一点?
答案 0 :(得分:4)
我建议将基类添加到名为ItemChange<T>
的{{1}}。 ItemChange
可以声明When属性。然后,将列表内容强制转换为基础ItemChange
以进行连接并按顺序排序。
ItemChange
答案 1 :(得分: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>
或ItemChange<Object1>
创建ItemChange<Object2>
的新实例。
根据您的使用情况,您可能希望将.ToList()
添加到Linq的末尾以提高性能。
答案 2 :(得分: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);
}
答案 3 :(得分:0)
如果您定义了一个接口IReadableItemChange<out T>
,它显示了T
类型的只读属性,而不是该类型的字段,并且ItemChange<T>
已实现IReadableItemChange<T>
,则{ {1}}和ItemChange<Derived1>
会为ItemChange<Derived2>
实现IReadableItemChange<MyBase>
(IReadableItemChange<baseType>
baseType
,Derived1:baseType
和Derived2:baseType
。对于ItemChange<T>
来说,拥有一个接受IReadableItemChange<T>
并从中复制数据的构造函数也可能会有所帮助。