c# – 循环引用 – 架构问题

前端之家收集整理的这篇文章主要介绍了c# – 循环引用 – 架构问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这可能是一个非常初学的问题,但我已经搜索了很多主题并且无法找到相同的情况,尽管我确信这种情况一直都在发生.

我的项目/计划将跟踪建筑项目图纸的变化,并在更改图纸时向人们发送通知.

将有许多建筑项目(工地),每个建筑项目中都会有很多图纸.每个图纸都会有一些修改(当它们被更改时,会创建一个新版本).

这是我的项目类

public class Project
{
    private readonly List<Drawing> _drawings = new List<Drawing>(30);
    private readonly List<Person> _autoRecepients = new List<Person>(30);

    public int ID { get; private set; }
    public string ProjectNumber { get; private set; }
    public string Name { get; private set; }
    public bool Archived { get; private set; }
    public List<Person> AutoRecepients { get { return _autoRecepients; } }


    public Project(int id,string projectNumber,string name)
    {
        if (id < 1) { id = -1; }

        ID = id;
        ProjectNumber = projectNumber;
        Name = name;
    }


    public bool AddDrawing(Drawing drawing)
    {
        if (drawing == null) return false;
        if (_drawings.Contains(drawing)) { return true; }

        _drawings.Add(drawing);

        return _drawings.Contains(drawing);
    }


    public void Archive()
    {
        Archived = true;
    }

    public bool DeleteDrawing(Drawing drawing)
    {
        return _drawings.Remove(drawing);
    }

    public IEnumerable<Drawing> ListDrawings()
    {
        return _drawings.AsReadOnly();
    }

    public override string ToString()
    {
        return string.Format("{0} {1}",ProjectNumber,Name);
    }
}

这是我的绘画课

public class Drawing : IDrawing
{
    private List<IRevision> _revisions = new List<IRevision>(5);
    private List<IssueRecord> _issueRecords = new List<IssueRecord>(30);
    private IRevision _currentRevision;

    public int ID { get; private set; }
    public string Name { get; private set; }
    public string Description { get; set; }
    public Project Project { get; private set; }
    public IRevision CurrentRevision { get { return _currentRevision; } }


    public Drawing(int id,string name,string description,Project project)
    {
        // To be implemented
    }


    /// <summary>
    /// Automatically issue the current revision to all Auto Recepients
    /// </summary>
    public void AutoIssue(DateTime date)
    {
        AutoIssue(date,_currentRevision);
    }

    /// <summary>
    /// Automatically issue a particular revision to all Auto Recepients
    /// </summary>
    public void AutoIssue(DateTime date,IRevision revision)
    {

    }

    public void IssueTo(Person person,DateTime date,IRevision revision)
    {
        _issueRecords.Add(new IssueRecord(date,this,revision,person));

        throw new NotImplementedException();
    }


    public void IssueTo(Person person,DateTime date)
    {
        IssueTo(person,date,_currentRevision);
    }        

    public void IssueTo(IEnumerable<Person> people,DateTime date)
    {
        IssueTo(people,_currentRevision);
    }

    public void IssueTo(IEnumerable<Person> people,IRevision revision)
    {
        foreach (var person in people)
        {
            IssueTo(person,revision);
        }

    }

    public void Rename(string name)
    {
        if (string.IsNullOrWhiteSpace(name)) { return; }

        Name = name;
    }

    public void Revise(IRevision revision)
    {
        if (revision.Name == null ) return;

        _revisions.Add(revision);
        _currentRevision = revision;
    }

    public struct IssueRecord
    {
        public int ID { get; private set; }
        public DateTime Date { get; private set; }
        public IDrawing Drawing { get; private set; }
        public IRevision Revision { get; private set; }
        public Person Person { get; private set; }

        public IssueRecord(int id,IDrawing drawing,IRevision revision,Person person)
        {
            if (id < 1) { id = -1; }

            ID = id;
            Date = date;
            Drawing = drawing;
            Revision = revision;
            Person = person;
        }

    }
}

这是Revision结构

public struct Revision : IRevision
{        
    public int ID { get; private set; }
    public string Name { get; }
    public DateTime Date { get; set; }
    public IDrawing Drawing { get; }
    public IDrawingFile DrawingFile { get; private set; }

    public Revision(int id,IDrawingFile drawingFile)
    {
        if (name == null) { throw new ArgumentNullException("name","Cannot create a revision with a null name"); }
        if (drawing == null) { throw new ArgumentNullException("drawing","Cannot create a revision with a null drawing"); }
        if (id < 1) { id = -1; }

        ID = id;
        Name = name;
        Drawing = drawing;
        Date = date;
        DrawingFile = drawingFile;
    }

    public Revision(string name,IDrawingFile drawingFile)
        : this(-1,name,drawing,drawingFile)
    {

    }

    public Revision(string name,IDrawing drawing)
        : this(-1,DateTime.Today,null)
    {

    }

    public void ChangeID(int id)
    {
        if (id < 1) { id = -1; }

        ID = id;
    }

    public void SetDrawingFile(IDrawingFile drawingFile)
    {
        DrawingFile = drawingFile;
    }
}

我的问题是在绘图类中的项目引用和修订结构中的绘图引用.
好像有点代码味道?
它似乎也可能导致将来序列化问题.
有一个更好的方法吗?

绘图对象似乎有必要知道它属于哪个项目,这样如果我正在使用单个绘图对象,我就可以知道它们属于哪个项目.

类似地,每个修订版本基本上由图纸“拥有”或者是图纸的一部分.没有绘图,修订没有意义,所以它需要引用它所属的绘图?

任何建议将不胜感激.

解决方法

你所拥有的不仅仅是循环引用,而是两个例子

可以从两端导航的亲子关系.

是的,这是正常的,可接受的,不是代码味道.是的,一些序列化工具需要您提示.例如Newtonsoft.Json需要ReferenceLoopHandling.Ignore设置.

作为一个概念的导航性并不总是在OO设计中被讨论,这是不幸的,因为它只是你想要的概念. (这是UML中的明确术语).

您通常不需要从两端进行导航.父子关系通常仅从父对子编码.这很常见.例如,invoiceline类很少需要其父发票的显式字段,因为大多数应用程序仅在检索父发票后查看该行.

所以设计决定不是,

“没有绘画,修改是否有意义?”

“我是否需要找到仅给出修订版的图纸?”

我的猜测是你的修订就像发票行,而不需要导航到他们的父母.图纸的答案< - >项目对我来说并不明显. (这是关于您的域名的分析问题,而不是代码式问题).

这是OO代码sql之间的显着差异.在sql数据库中,它必须是包含对其父图形ID的引用的修订表.在OO代码中,父类几乎总是拥有对子代的引用.孩子们通常不需要引用他们的父母,因为你访问孩子的唯一方法是已经拥有父母.

猜你在找的C#相关文章