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();
}
}
}