什么是表示多个集合的数据结构?

时间:2013-03-05 17:30:58

标签: c# .net

我有一个像这样的对象的现有应用程序。

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吗?
如果不是我想建立什么样的数据结构?

5 个答案:

答案 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反映其他集合中的更改,即使它不允许您直接向其添加项目。