我有一个像这样的对象的现有应用程序。
class MyObject{
public MyCollection TypeOnes;
public MyCollection TypeTwos;
public MyCollection TypeThrees;
public MyCollection All;
}
class MyCollection : Collection{
public boolean IsLoaded;
}
就像这样加载。
//using bool array for flag simplicity in example
public void Load(ref MyObject obj, bool[] flags){
if(flags[0]){
obj.TypeOnes = LoadOnes();
obj.TypeOnes.IsLoaded = true;
}else{
obj.TypeOnes = new MyCollection();
}
if(flags[1]){
obj.TypeTwos = LoadTwos();
obj.TypeTwos.IsLoaded = true;
}else{
obj.TypeTwos= new MyCollection();
}
if(flags[2]){
obj.TypeThrees = LoadThrees();
obj.TypeThrees.IsLoaded = true;
} else {
obj.TypeThrees = new MyCollection();
}
if(flags[3]){
obj.All = obj.TypeOnes.Clone().AddRange(obj.TypeTwos.Clone()).AddRange(obj.TypeThrees.Clone());
obj.All.IsLoaded = true;
} else {
obj.All = new MyCollection();
}
}
正如您可以清楚地看到,应该代表所有类型的All
集合将不同步,除非使用All
集合一次性加载所有类型。
我要做的是制作一个标志来加载所有类型集合,但是,我希望保留All
集合,以便一次访问所有类型集合并具有它们是同步的,以限制我将要做的重构量。我希望它是可读/写的,这样如果我对TypeOnes
集合进行更改,它将反映在All
集合中,反之亦然。
我可以使用现有的DataType吗?
如果不是我想建立什么样的数据结构?
答案 0 :(得分:4)
除非您有特定的理由在三个包含的集合中创建对象的克隆,否则为什么不将All
实现为IEnumerable<T>
(如果您使用的是预先通用的.NET,则为IEnumerable ),类似于:
// Option: Preserve duplicates between collections
public IEnumerable<T> All()
{
// Ensure child collections are loaded
return TypeOnes.Concat(TypeTwos).Concat(TypeThrees);
}
// Option remove duplicates between collections
public IEnumerable<T> All()
{
// Ensure child collections are loaded
return TypeOnes.Union(TypeTwos).Union(TypeThrees);
}
这样就可以维护现有的代码合同,以便将内容添加到包含的集合中,并确保All
永远不会过时或与这些集合不同步。
请注意,使用旧代码合同,All
在初始化后与包含的集合变得不同步(因为对子项的更新未反映到All
)。这是行为的改变,可能是也可能是不可接受的。
答案 1 :(得分:2)
这样的事情怎么样? Concat
将合并集合并立即返回所有集合。
class MyObject
{
public MyCollection TypeOnes;
public MyCollection TypeTwos;
public MyCollection TypeThrees;
public IEnumerable<T> All
{
get { return TypeOnes.Concat(TypeTwos.Concat(TypeThrees));}
// You can use Union() to handle duplicates as well, but it's slower.
}
}
答案 2 :(得分:2)
可能的方法 - 揭露&#34;所有&#34;作为IEnumerable<Base_type_for_items_in_other_collections>
并通过连接其他集合按需创建它。即如果你有一个小的集合列表,基本Enumerable.Concat将起作用:
public IEnumerabe<MyObject> All {get
{
return TypeOnes.Concat(TypeTwos.Concat(TypeThrees));
}}
答案 3 :(得分:0)
由于可能有很多项目,您可以考虑yield return
来返回项目,这样当达到适当的限制/找到项目时,来电者就可以停止访问项目。
public class MyObject
{
public MyCollection TypeOnes { get; set;}
public MyCollection TypeTwos { get; set;}
public MyCollection TypeThrees { get; set;}
public IEnumerable<string> All
{
get
{
foreach (var item in TypeOnes.Union(TypeTwos).Union(TypeThrees))
{
yield return item;
}
}
}
}
public class MyCollection : Collection<string>
{
public bool IsLoaded { get; set; }
}
答案 4 :(得分:0)
你真正需要的是一个ICollection接口或IEnumerable接口,它涵盖了工会中的所有其他集合,对吧?我假设一旦你加载了所有东西,你就不会在All集合中添加项目。如果是这种情况,请尝试:
宣布全部:
public IEnumerable<MyBaseType> All;
设置全部:
obj.All = System.Linq.Enumerable.Concat<MyBaseType>(
obj.TypeOnes, obj.TypeTwos).Concat(obj.TypeThrees);
这应该允许All反映其他集合中的更改,即使它不允许您直接向其添加项目。