Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何处理将父对象作为参数传递?_C# - Fatal编程技术网

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

C# 如何处理将父对象作为参数传递?,c#,C#,我不确定我所做的是完全无效还是仅仅是拙劣的实践,但我有一个类,我们称之为Bar,它是某个父类的字段,我们称之为Foo,其中一个Bar方法要求我将父类的实例作为参数传递。这似乎是一个糟糕而混乱的想法,但我想不出更好的办法Foo有效地存储了大量的列表、条码、ConcurrentDictionary,或类似内容,并允许我构建所有的条码实例,而无需重复数据 该准则的原则如下: public class Foo { public List<Bar1> bar1List {get;set

我不确定我所做的是完全无效还是仅仅是拙劣的实践,但我有一个类,我们称之为
Bar
,它是某个父类的字段,我们称之为
Foo
,其中一个
Bar
方法要求我将父类的实例作为参数传递。这似乎是一个糟糕而混乱的想法,但我想不出更好的办法
Foo
有效地存储了大量的
列表
条码
ConcurrentDictionary
,或类似内容,并允许我构建所有的
条码
实例,而无需重复数据

该准则的原则如下:

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.
公共类Foo
{
公共列表栏1列表{get;set;}
公共列表bar2List{get;set;}
}
公共抽象类栏
{
//编辑以改进示例
公共int值{get;set;}
公共无效DoSomething(Foo parentFoo)
{
}
}
公共类酒吧1:酒吧
{
公共覆盖无效DoSomething(Foo parentFoo)
{
//编辑以给出DoSomething()的示例
this.Value=this.Value+parentFoo.bar2List[0]。值:
}
}
公共类酒吧2:酒吧
{
公共覆盖无效DoSomething(Foo parentFoo)
{
//其他代码
}
}
Foo Foo=新Foo()
//以某种方式填充foo
foo.bar1列表[0]。剂量测定法(foo);
//这在我看来很奇怪,感觉就像一个循环引用。代码永远不会是循环的,因为如果我想在DoSomething()中更改bar1List,我将通过“this”来完成,而不是foo.bar1List。
我想让每个
列表
(其中X是一个数字)成为
BarX的静态字段
,但这不起作用,因为所有内容都是多线程的,我想要多个
列表
;我曾考虑过使用标准方法访问父对象,但如果一个
列表中有两个父对象,我不认为这不会变得混乱。有什么想法/提示吗?我不想将
DoSomething
方法移出
Bar

编辑以描述实际问题:
如前所述,
Foo
作为所有
Bar
实例的存储库;所有
Bar
实例都是相互交织的,因此
Bar1
可能包含一个
列表。一系列
s,例如
列表
被指定为程序输入;其余的
BarX
列表等将根据需要使用配置文件和逻辑从该列表中创建。总共有9种口味的
Bar
,以非线性方式排列,例如,我的第一个
Bar1
实例可能需要一个
Bar7
实例,而这又需要另一个
Bar1
实例(在最初的
列表中不存在)等等。每个
BarX
flavor都有一个
Generate()。这种安排非常适合线程,因此需要一个并发的位置来保存所有这些实例,其中基本思想是IfExists,返回它并分配给field/List/which;否则,构建它并将其添加到
ConcurrentDictionary
实现这一点的方法之一是为
Foo
类实现
ObservableCollection
以侦听列表中的更改,并且在添加/删除项时,可以将父项添加到子栏项

这样,您的方法不必引用父对象,但它可以通过属性
parent
访问它,该属性的类型为
Foo

因为它们都会在
Foo
实例中引用相同的
Foo
实例,所以不会有重复的数据

作为这种实现的一个例子,您可以这样做

首先定义一个接口,该接口提供对父属性的轻松访问

public interface IChild<T>
{
    T Parent { get; }
}
在一个抽象版本的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();
}
然后,您仍然需要对
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);
    }
}

您可以将
列表
实现为
IList
,并使用
可观察集合
,同时向
Foo
类型的
添加名为
父项
的属性。每次添加或删除项目时,可观察集合都会触发一个
INotifyCollectionChanged
事件,您可以将
Bar
Parent
属性设置/取消设置为
Foo
this
)变量?这取决于
DoSomething
对父对象的操作。通常,如果它只使用几个属性,那么您可能应该将这些属性作为参数传递给
DoSomething
。但是如果它需要在父级上调用方法,可以将它们作为委托传递,也可以传递父级。有很多方法可以通知父母孩子的情况发生了变化。如果没有更多关于
DoSomething
做什么的信息,就很难给出建议。这看起来确实“不对”,但因为我们不知道
DoSomething
foo
做了什么,所以没有办法提出任何建议。。。如果您描述的是实际的场景而不是任意的类,这将非常有用。我在这里使用@AntP,这是一个典型的X-Y问题,您正在尝试为另一个问题找到解决方案。你能描述一下,你到底想达到什么目的吗?看看这个
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");
    }
}
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();
        }
    }
}