如何处理传递父对象作为参数?

时间:2015-05-11 17:01:35

标签: c#

我不确定我所做的事情是完全无效还是仅仅是糟糕的练习,但我有一个课程,让我们称之为Bar,这是一个父类的字段,让&# 39; s调用FooBar方法之一要求我传递父Foo的实例作为参数。这似乎是一个糟糕而混乱的想法,但我无法想到一个更好的方法。 Foo有效地存储了一些List<Bar>BarConcurrentDictionary<string,Bar>或类似内容,用于允许我构建所有Bar个实例,而无需重复数据。

代码的原理是这样的:

public class Foo
{
    public List<Bar1> bar1List {get;set;}
    public List<Bar2> bar2List {get;set;}
}

public abstract class Bar
{
    //EDITED TO IMPROVE EXAMPLE
    public int Value {get;set;}
    public void DoSomething(Foo parentFoo)
        {
        }
}

public class Bar1 : Bar
{
    public override void DoSomething(Foo parentFoo)
        {
        //EDITED TO GIVE AN EXAMPLE OF DoSomething()
            this.Value = this.Value + parentFoo.bar2List[0].Value:
        }
}

public class Bar2 : Bar
{
    public override void DoSomething(Foo parentFoo)
        {
        //some other code
        }
}

Foo foo = new Foo()
//populate foo somehow

foo.bar1List[0].DoSomething(foo);
//this is what looks very odd to me and feels kind of like a circular reference. The code will never be circular in that if I want to change bar1List within DoSomething() I will do it by "this", not foo.bar1List.

我考虑过将每个List<BarX>(其中X是一个数字)作为BarX的静态字段,但这不起作用,因为所有内容都是多线程的,我想要{{1}的多个实例1}};我考虑过使用标准方法访问父对象,但是如果我有一个List<BarX>的父母,我就不知道如何弄乱它。有什么想法/提示吗?我不想将List<BarX>方法移出DoSomething

编辑实际问题说明: 如前所述,Bar充当所有各种Foo实例的存储库;所有Bar个实例都是交织在一起的,因此Bar可能包含Bar1List<Bar>的一个家族,例如Bar被规定为程序输入;然后使用配置文件和逻辑的wholo加载,从此List创建剩余的List<Bar1>列表等等。总共有9种BarX种口味,以非线性方式排列,例如我的第一个Bar实例可能需要一个Bar1实例,而后者又需要另一个Bar7实例(初始Bar1中没有该实例),依此类推。每个List<Bar1>风格都有一个BarX方法,取代Generate()来确定如何构建它。这种安排非常适合线程,因此需要一个Concurrent来保存所有这些实例,其中基本思想是IfExists,返回它并分配给field / List / whatever;否则建立它并将其添加到DoSomething()

1 个答案:

答案 0 :(得分:3)

实现此类目标的方法之一是为ObservableCollection类实现Foo以监听列表中的更改,并在添加/删除项目时添加子项目的父项。

像这样,您的方法不必引用父级,但可以通过类型为Parent的属性Foo访问它。

由于他们都会在Foo实例上引用Foo的同一个实例,因此您不会重复数据。

作为此类实现的一个示例,您可以这样做

首先定义一个可以轻松访问Parent属性的接口

public interface IChild<T>
{
    T Parent { get; }
}

我们可以对Bar的DoSomething方法做同样的事情

public interface IBar
{
    void DoSomething();
}

并在Abstract的Bar中实现两个接口,留下DoSomething方法摘要

public abstract class Bar : IChild<Foo>, IBar
{
    private Foo parent;
    public Foo Parent
    {
        get
        {
            return parent;
        }
        set
        {
            parent = value;
        }
    }

    public abstract void DoSomething();
}

并实现Bar的2个版本,例如:

public class Bar1 : Bar
{
    public override void DoSomething()
    {
        if (this.Parent == null)
        {
            throw new ArgumentException("Parent cannot be null");
        }
        // code against parent
        Console.WriteLine("Bar 1 doing something");
    }
}

public class Bar2 : Bar
{
    public override void DoSomething()
    {
        if (this.Parent == null)
        {
            throw new ArgumentException("Parent cannot be null");
        }
        // code against parent
        Console.WriteLine("Bar 2 doing something");
    }
}

然后,您需要对Foo类进行一些更改,将其自身注册到集合(Bar1Collection,Bar2Collection),并提供一种方法来监听集合中的更改。它还实现了IDisposable接口,以便我们可以在不再需要Foo类时从CollectionChanged事件中取消注册

public class Foo : IDisposable
{
    private readonly IList<Bar> bar1Collection = new ObservableCollection<Bar>();
    public IList<Bar> Bar1Collection
    {
        get
        {
            return bar1Collection;
        }
    }

    private readonly IList<Bar> bar2Collection = new ObservableCollection<Bar>();
    public IList<Bar> Bar2Collection
    {
        get
        {
            return bar2Collection;
        }
    }

    protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.OldItems != null)
        {
            foreach (var item in e.OldItems)
            {
                if (item is Bar)
                {
                    var bar = item as Bar;
                    bar.Parent = null;
                }
            }
        }
        if (e.NewItems != null)
        {
            foreach (var item in e.NewItems)
            {
                if (item is Bar)
                {
                    var bar = item as Bar;
                    bar.Parent = this;
                }
            }
        }
    }

    protected void RegisterCollection(INotifyCollectionChanged collection)
    {
        if (collection == null)
        {
            return;
        }
        collection.CollectionChanged += OnCollectionChanged;
    }

    protected void UnregisterCollection(INotifyCollectionChanged collection)
    {
        if (collection == null)
        {
            return;
        }
        collection.CollectionChanged -= OnCollectionChanged;
    }

    public Foo()
    {
        RegisterCollection(Bar1Collection as INotifyCollectionChanged);
        RegisterCollection(Bar2Collection as INotifyCollectionChanged);
    }

    private bool isDisposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing || isDisposed)
        {
            return;
        }
        isDisposed = true;
        UnregisterCollection(Bar1Collection as INotifyCollectionChanged);
        UnregisterCollection(Bar2Collection as INotifyCollectionChanged);
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

作为一种测试方法,该控制台程序可以针对它运行

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;

namespace BarFoo
{
    class Program
    {
        static void Main(string[] args)
        {
            Foo foo1 = new Foo();
            Bar bar1 = new Bar1();
            Bar bar2 = new Bar2();
            foo1.Bar1Collection.Add(bar1);
            foo1.Bar2Collection.Add(bar2);
            Debug.Assert(bar1.Parent != null);
            Debug.Assert(bar2.Parent != null);
            bar1.DoSomething();
            bar2.DoSomething();
            Console.WriteLine("Done");
            Console.ReadLine();
            foo1.Dispose();
        }
    }
}