2

我有一个现有的应用程序,其中包含这样的对象。

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?
如果不是,我希望构建什么样的数据结构?

4

5 回答 5

4

除非您有特定原因要在三个包含的集合中创建对象的克隆,否则为什么不实现AllIEnumerable<T>(或 IEnumerable,如果您使用的是 pre-generic .NET),例如:

// 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. 这是一种行为变化,可能会也可能不会被接受。

于 2013-03-05T17:37:36.677 回答
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.
    }
}
于 2013-03-05T17:37:28.947 回答
2

可能的方法 - 公开“全部”IEnumerable<Base_type_for_items_in_other_collections>并通过连接其他集合按需创建它。即,如果您有一个小的集合列表,则基本Enumerable.Concat会起作用:

public IEnumerabe<MyObject> All {get
{
   return TypeOnes.Concat(TypeTwos.Concat(TypeThrees));
}}
于 2013-03-05T17:37:50.447 回答
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; }
}
于 2013-03-05T17:45:10.450 回答
0

您真正需要的只是一个 ICollection 接口或 IEnumerable 接口,它涵盖了联合中的所有其他集合,对吗?我假设您在加载完所有内容后不会将项目添加到 All 集合中。如果是这种情况,请尝试:

对于 All 的声明:

public IEnumerable<MyBaseType>  All;

全部设置:

obj.All = System.Linq.Enumerable.Concat<MyBaseType>(
          obj.TypeOnes, obj.TypeTwos).Concat(obj.TypeThrees);

这应该允许 All 反映其他集合中的更改,即使它不允许您直接向其中添加项目。

于 2013-03-05T17:48:44.937 回答