简体   繁体   中英

C# multi level object and list access

I have no idea what should this question be titled nor keyword to search.

Scenario : I have a model as below

public class Message { public List<Page> Pages { get; set; }
public class Page { public List<Line> Lines { get; set; }
public class Line { public string Text {get; set; }

When I wanted to insert a Line with Text = "Test" at Page 1, I would need to do the following.

var Message = new Message();
var line = new Line { Text = "Test" };
var page = new Page();
page.Lines.Add(line);
Message.Pages.Add(page);

Question : are there any easier way to achieve this? Eg.

Message.Pages[0].Lines[0].Text = "Test";

Thanks.

Edit : Assumed all properties are properly instantiated in constructors.

var msg = new Message {
    Pages = new List<Page> {
        new Page {
            Lines = new List<Line> { new Line { Text = "Test" } }
        }
    }
};

Note: if the lists are initialized in their respective constructors, you can remove the new List<> bits:

var msg = new Message {
    Pages = {
        new Page {
            Lines = { new Line { Text = "Test" } }
        }
    }
};

You could also add an implicit conversion operator from string to Line , in which case:

var msg = new Message {
    Pages = {
        new Page {
            Lines = { "Test" }
        }
    }
};

Edit: fully working example, including operator and ctor initialization, and multiple pages (see comments):

using System.Collections.Generic;

public class Message {
    public List<Page> Pages { get; private set; }
    public Message() { Pages = new List<Page>(); }
}
public class Page {
    public List<Line> Lines { get; private set; }
    public Page() { Lines = new List<Line>(); }
}
public class Line {
    public string Text { get; private set; }
    public static implicit operator Line(string value) {
        return new Line { Text = value };
    }
}

static class Program {
    static void Main() {
        var msg = new Message {
            Pages = {
                new Page {
                    Lines = { "Test" }
                },
                new Page {
                    Lines = {
                        "On another page",
                        "With two lines"
                    },
                }
            }
        };
    }
}

You can create helper methods in your classes, which will provide handy API for building messages and pages. First is Message class - new Add method accepts page to add, and returns message instance. That will allow to use fluent API for adding pages (example at the bottom):

public class Message
{
    public Message()
    {
        Pages = new List<Page>();
    }

    public List<Page> Pages { get; private set; }

    public Message Add(Page page)
    {
       Pages.Add(page);
       return this;
    }
}

And page class. I added static creation method, which builds page with any number of lines you pass to this method:

public class Page 
{
    public Page() 
    {
        Lines = new List<Line>();
    }

    public List<Line> Lines { get; private set; }

    public static Page WithLines(params string[] texts)
    {
        var page = new Page();

        foreach(var text in texts)
           page.Lines.Add(new Line { Text = text });

        return page;
    }
}

Then adding page with lines will look like

message.Add(Page.WithLines("Text1", "Text2"))
       .Add(Page.WithLines("Text3"));

What Marc and Sergey said. Also you can consider a simplified builder. I replaced the properties with fields to make the example smaller:

public class Message { public List<Page> Pages = new List<Page>(); }
public class Page { public List<Line> Lines = new List<Line>(); }
public class Line { public string Text; }

Then your builder would look something like this:

public class Typewriter
{
    Message message = new Message();
    Page currentPage;

    public Typewriter NewPage()
    {
        currentPage = new Page();
        message.Pages.Add(currentPage);
        return this;
    }

    public Typewriter AddLine(string text)
    {
        currentPage.Lines.Add(new Line() { Text = text });
        return this;
    }
}

Then you can do:

var typewriter = new Typewriter();
typewriter.NewPage().AddLine("First line on first page")
    .AddLine("Next line on first page")
    .NewPage().AddLine("Next page etc");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM