[英]How can i concatenate two different list<T> where both have same base class?
I have a class called ItemChange<T>
that looks like this: 我有一个叫做
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;
}
As you can see it stores two copies of an object ( NewState
and OldState
). 如您所见,它存储对象的两个副本(
NewState
和OldState
)。 I use this to compare field changes. 我用它来比较字段更改。
I now am trying to get this to work where I get a list of changes across multiple objects and then concatenate a few different types of T list into one array like this (NOTE: both Object1
and Object2
derive from MyBase
: 我现在正在尝试使其工作,在该操作中我获得多个对象的变化列表,然后将几种不同类型的T列表连接到一个数组中,如下所示(注意:
Object1
和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);
}
As you can see I need to concatenate changes from multiple types but then I want to grab the most recent number of changes (defined by numberOfChanges
) 如您所见,我需要将多种类型的更改串联起来,但是然后我想获取最新的更改数量(由
numberOfChanges
定义)
Any suggestions for how I could get the below to work as the Concat line gives me a compiler error (I assume I have to cast in some special way to get this to work). 关于如何使以下内容在Concat行中工作的任何建议都给了我一个编译器错误(我认为我必须以某种特殊的方式进行转换才能使其正常工作)。
Is there any way to do that? 有什么办法吗?
I recommend adding a base class to ItemChange<T>
called ItemChange
. 我建议向
ItemChange<T>
添加一个称为ItemChange
的基类。 The ItemChange
can declare the When property. ItemChange
可以声明When属性。 Then it becomes pretty easy to cast the list contents to the base ItemChange
for concat and order by. 然后,将列表内容
ItemChange
为基本的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());
}
}
}
How about this? 这个怎么样? I am not sure because I cannot test it now.
我不确定,因为我现在无法测试。
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);
}
It creates a new instance of ItemChange<MyBase>
from ItemChange<Object1>
or ItemChange<Object2>
. 它从
ItemChange<Object1>
或ItemChange<Object2>
创建ItemChange<MyBase>
的新实例。
Depending on your usage, you may want to add .ToList()
to the end of the Linq to increase performance. 根据您的使用情况,您可能需要在Linq的末尾添加
.ToList()
以提高性能。
What you are trying to do is not safe since there is no conversion between an ItemChange<Object1>
and an ItemChange<Object2>
, and there is certainly no conversion to some arbitrary ItemChange<T>
. 您尝试执行的操作并不安全,因为在
ItemChange<Object1>
和ItemChange<Object2>
之间没有转换,并且当然也没有到任意的ItemChange<T>
转换。 The best you can try to do is ItemChange<MyBase>
but classes are not covariant in C# so this is not valid: 您可以尝试做的最好的事情是
ItemChange<MyBase>
但是C#中的类不是协变的,因此这是无效的:
ItemChange<MyBase> change = new ItemChange<Object1>();
You therefore cannot cast an IEnumerable<ItemChange<Object1>>
to an IEnumerable<ItemChange<Object2>>
. 因此,您不能将
IEnumerable<ItemChange<Object1>>
转换为IEnumerable<ItemChange<Object2>>
。
However if you create an interface for your ItemChange<T>
class then you can do it safely: 但是,如果为
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; }
}
You can then change your GetChanges
and GetChangeHistory
methods to: 然后,您可以将
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);
}
If you defined an interface IReadableItemChange<out T>
which exposed read-only properties of type T
rather than fields of that type, and if ItemChange<T>
implemented IReadableItemChange<T>
, then both ItemChange<Derived1>
and ItemChange<Derived2>
would implement IReadableItemChange<MyBase>
(and, incidentally, IReadableItemChange<baseType>
for any baseType
such that Derived1:baseType
and Derived2:baseType
). 如果定义了接口
IReadableItemChange<out T>
,该接口公开了类型T
只读属性,而不是该类型的字段,并且如果ItemChange<T>
实现了IReadableItemChange<T>
,则ItemChange<Derived1>
和ItemChange<Derived2>
都将实现IReadableItemChange<MyBase>
(以及对任何baseType
例如Derived1:baseType
和Derived2:baseType
)的IReadableItemChange<baseType>
)。 It may be helpful as well for ItemChange<T>
to have a constructor which accepts an IReadableItemChange<T>
and copies the data from it. 对于
ItemChange<T>
,拥有一个接受IReadableItemChange<T>
并从中复制数据的构造函数也可能会有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.