Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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#_Oop - Fatal编程技术网

C# 如何在类中交叉引用对象

C# 如何在类中交叉引用对象,c#,oop,C#,Oop,我有一个Person类和两个继承的类Parent和Child。父级可以有n个子级,子级可以有n个父级 在OOD中,在父母和孩子之间创建引用的最佳方式是什么 我应该在每个类中创建一个引用连接的父/子类的列表,还是有更好的方法?如果您可以将关联的方向限制为只有一个方向,您将为自己省去很多麻烦(但这并不总是可能的) 单向关系: public class Parent : Person { public IEnumerable<Person> Children { get; } }

我有一个Person类和两个继承的类Parent和Child。父级可以有n个子级,子级可以有n个父级

在OOD中,在父母和孩子之间创建引用的最佳方式是什么


我应该在每个类中创建一个引用连接的父/子类的列表,还是有更好的方法?

如果您可以将关联的方向限制为只有一个方向,您将为自己省去很多麻烦(但这并不总是可能的)

单向关系:

public class Parent : Person
{
    public IEnumerable<Person> Children { get; }
}
然而,现在您需要维护一个循环引用,虽然这是可能的,但它并不是特别有效


通常,你可以让孩子们引发事件,而不是明确地引用他们的父母,从而将这种联系保持为单向关系。

我可以想象,一个孩子也可以是父母(如果他运气好……或者运气不好,这取决于他的观点),所以我会选择这样的方式:

IPerson
{
   string Name {get; set;}
   string LastName {get; set;}
   // whatever else - such as sizeOfShoe, dob, etc
}

IHaveParents
{
   // might wanna limit this to a fixed size
   List<IPerson> Parents {get; set;}
}

IHaveChildren
{
   List<IPerson> Children {get; set;}
}

IHaveSpouse
{
   IPerson Spouse {get; set;}
}

public class DudeWithParentsAndChildren : IPerson, IHaveParents, IHaveChildren, IHaveSpouse
{       
   public void AskMoneyToParents(){throw new Exception("Implement me!");}
   public void SlapChildren(){}
   private void CheatOnSpouse(){}
   // some other stuff that such a dude can do i.e. GoBowling
}
public class Child : IPerson, IHaveParents
{       
   public void AskMoneyToParents(){throw new Exception("Implement me!");}
}

public class Parent : IPerson, IHaveChildren, IHaveSpouse
{       
   public void SlapChildren(){}
   private void CheatOnSpouse(){}
   // some other stuff that such a dude can do i.e. GoBowling
}

如果您想拥有IHaveFriends接口,可以这样做(这基本上迫使实现者将IPERSON列表公开为名为Friends的属性)。如果你不需要它,就不要去做,但事实上,你只需添加一个接口就可以轻松地去做,其他一切都保持不变,这意味着你有了一个相当不错的可扩展模型(不一定是最好的,你知道我的意思)。

正如约翰·尼多指出的那样,一个处于劣势的孩子可能会成为父母。换句话说,不要将父类和子类划分为Person

class Person
{
   readonly List<Person> _children = new List<Person>(), 
                         _parents = new List<Person>();

   public IEnumerable<Person> Children 
   { 
      get { return _children.AsReadOnly(); } 
   }

   public IEnumerable<Person> Parents 
   { 
      get { return _parents.AsReadOnly(); } 
   }

   public void AddChild(Person child)
   {
       _children.Add(child);
       child._parents.Add(this);
   }

   public void AddParent(Person parent)
   {
       _parents.Add(parent);
       parent._children.Add(this);
   }

   /* And so on... */
}
班级人员
{
只读列表_children=新列表(),
_父项=新列表();
可数儿童的公共教育
{ 
获取{return _children.AsReadOnly();}
}
公共数字家长
{ 
获取{return _parents.AsReadOnly();}
}
公共无效添加子对象(个人子对象)
{
_添加(child);
孩子。_父母。添加(此);
}
公共无效添加父对象(个人父对象)
{
_parents.Add(parent);
父项。\u子项。添加(此项);
}
/*等等*/
}
公共类人员
{
个人家长{get;set;}
IList子项{get;set;}
}
当您不知道父项时,父项可以为null。 没有子项时,子项可以为null或空。 因为每个孩子都是一个人,所以可以有父母或自己的孩子


这种设计本身是好的,直到您提供关于如何使用或持久化它的更详细的用例场景

好问题。纯多对多关系实际上非常罕见,引入一个中间对象来建模关系本身通常会有所帮助。如果(当!)出现需要捕获关系属性的用例(例如,子/父关系是否为自然关系、代理关系、收养关系等),这将证明是非常宝贵的

因此,除了您已经确定的Person、Parent和Child实体之外,让我们介绍一个名为ParentChildRelationship的对象。 ParentChildRelationship的实例将只引用一个父类和一个子类,父类和子类都将包含这些实体的集合

然后,最好确定使用这些实体的用例,并添加适当的帮助器方法来维护对象间引用。 在下面的示例中,我刚刚选择向父级添加一个公共AddChild方法

public abstract class Person
{
}

public class Parent : Person
{
    private HashSet<ParentChildRelationship> _children = 
        new HashSet<ParentChildRelationship>();

    public virtual IEnumerable<ParentChildRelationship> Children
    {
        get { return this._children; }
    }

    public virtual void AddChild(Child child, RelationshipKind relationshipKind)
    {
        var relationship = new ParentChildRelationship()
        {
            Parent = this,
            Child = child,
            RelationshipKind = relationshipKind
        };

        this._children.Add(relationship);
        child.AddParent(relationship);
    }
}

public class Child : Person
{
    private HashSet<ParentChildRelationship> _parents = 
        new HashSet<ParentChildRelationship>();

    public virtual IEnumerable<ParentChildRelationship> Parents
    {
        get { return this._parents; }
    }

    internal virtual void AddParent(ParentChildRelationship relationship)
    {
        this._parents.Add(relationship);
    }
}

public class ParentChildRelationship
{
    public virtual Parent Parent { get; protected internal set; }

    public virtual Child Child { get; protected internal set; }

    public virtual RelationshipKind RelationshipKind { get; set; }
}

public enum RelationshipKind
{
    Unknown,
    Natural,
    Adoptive,
    Surrogate,
    StepParent
}

公共抽象类人物
{
}
公共类家长:个人
{
私有哈希集_子项=
新HashSet();
公共虚拟可数子对象
{
获取{返回此。_children;}
}
公共虚拟void AddChild(Child-Child,RelationshipKind-RelationshipKind)
{
变量关系=新的ParentChildRelationship()
{
父=此,
孩子,
RelationshipKind=RelationshipKind
};
此._children.Add(关系);
添加父母(关系);
}
}
公营儿童:人
{
私有哈希集_父项=
新HashSet();
公共虚拟可数父对象
{
获取{返回此。\u parents;}
}
内部虚拟void AddParent(ParentChildRelationship)
{
此._parents.Add(关系);
}
}
公共阶级亲子关系
{
公共虚拟父级{get;受保护的内部集;}
公共虚拟子项{get;受保护的内部集;}
公共虚拟关系类RelationshipKind{get;set;}
}
公共枚举关系类型
{
不详,
自然,,
收养的,
代理
继父
}

事实上,在我的示例中,孩子永远不会成为家长,早在那之前它就被扔出了系统:-)很酷-但这只是一个示例,我试图传达的信息是,我仍然会创建子类和父类,让它们分别实现那些IHaveParents和IHaveChildren(IPerson除外)好的,但在我的示例中,是否可以只使用接口IHaveChildOrParent?我不是说这会很好,只是想知道是否有可能分享这两者,以及是否有任何优势。请参阅编辑-如果我理解正确,这就是我在您的情况下会做的事情。您是否选择引入具体的父类和子类真的取决于正在开发的系统的性质。如果是系谱/家谱软件,那么我同意您只需要一个具体的Person类。但是,如果您正在开发跟踪子女抚养费/福利金支付的软件,则可能需要针对父母和子女的具体类,因为这些实体将具有完全不同的属性,并且子女最终可能成为父母这一事实与系统无关。图像缺失。。。你能把这张照片贴在imgur上吗
public class Person
{
    Person Parent { get;set; }
    IList<Person> Children { get;set; }
}
public abstract class Person
{
}

public class Parent : Person
{
    private HashSet<ParentChildRelationship> _children = 
        new HashSet<ParentChildRelationship>();

    public virtual IEnumerable<ParentChildRelationship> Children
    {
        get { return this._children; }
    }

    public virtual void AddChild(Child child, RelationshipKind relationshipKind)
    {
        var relationship = new ParentChildRelationship()
        {
            Parent = this,
            Child = child,
            RelationshipKind = relationshipKind
        };

        this._children.Add(relationship);
        child.AddParent(relationship);
    }
}

public class Child : Person
{
    private HashSet<ParentChildRelationship> _parents = 
        new HashSet<ParentChildRelationship>();

    public virtual IEnumerable<ParentChildRelationship> Parents
    {
        get { return this._parents; }
    }

    internal virtual void AddParent(ParentChildRelationship relationship)
    {
        this._parents.Add(relationship);
    }
}

public class ParentChildRelationship
{
    public virtual Parent Parent { get; protected internal set; }

    public virtual Child Child { get; protected internal set; }

    public virtual RelationshipKind RelationshipKind { get; set; }
}

public enum RelationshipKind
{
    Unknown,
    Natural,
    Adoptive,
    Surrogate,
    StepParent
}