-2

I have two classes representing a master detail relationship, where the master object contains the details and the detail object references the master. I'm trying to use object initialization to instantiate them, but not sure how to pass the master reference into the detail... Maybe not possible, but wanted to ask.

I have the following classes:

public class Detail
{
    public Detail(string type, string value, Entity entity) {...}
    public string Value { get; set; }

    public Master Master { get; set; }
}

public class Master
{
    public string ID { get; set; }

    public IEnumerable<Detail> Details{ get; set; }
}

If I want to use object initializers how can I pass the master reference into the detail instance?

List<Master> = new List<Master>()
{
    new Master()
    {
        Details= new List<Detail>()
        {
             new Detail()
             {
                 Master = ???
             } 
        }
    }
};
Jeremy
  • 44,950
  • 68
  • 206
  • 332
  • It's not possible to use object initialization like this. Even with normal constructors you can't do this. You'd need to use a factory method to get anything funky like this to work. – Enigmativity Sep 10 '20 at 22:59
  • Implementing what @Enigmativity said inside `Details.Add` would make initialization look nicer... but that is way outside of the requirement to have `IEnumerable`. – Alexei Levenkov Sep 10 '20 at 23:09
  • Is there any chance you could make the `Detail` class actually compilable? – Enigmativity Sep 10 '20 at 23:17
  • Here's how I would tackle this kind of thing: https://dotnetfiddle.net/zNHnMA – Enigmativity Sep 10 '20 at 23:47

2 Answers2

1

Disregarding the fact your code is full of errors, you can't use object initialization to reference parts of the parent graph. You either need to use a constructor, helper, setter, or set it after the fact:

public class Master()
{
     public Master(List<Detail> details)
     {
         details.ForEach(x => x.Master = this);
         Details = details;
     }
     ...
}

Usage:

List<Master> = new List<Master>()
{
    new Master(new List<details>{...})
}

or example after the fact, since Details is an IEnumerable<T>:

list.ForEach(x => x.Details.ToList().ForEach(y => y.Master = x));
halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • yea, it does have errors. I basically wrote that code in the editor window here. oops. but it gets the point across which is what it needs to do :) – Jeremy Sep 16 '20 at 20:27
  • sorry, what's wrong with details being an IEnumerable? – Jeremy Sep 16 '20 at 20:31
  • @Jeremy nothing really, except you have to `ToList()` before you can `ForEach` – TheGeneral Sep 16 '20 at 21:20
  • I don't think tat's true. An IEnumerable<> supports foreach. And if you had to ToList for a foreach that would negate the concept of deferred execution. – Jeremy Sep 17 '20 at 15:14
  • @Jeremy ForEach not foreach. If you need this deferred you cannt insert the parent until it's enumerated. – TheGeneral Sep 17 '20 at 21:10
1

You can do this by implementing a Master.Details as a full property that sets Detail.Master

public class Master
{
    public string ID { get; set; }

    public IEnumerable<Detail> Details
    {
        get => details;
        set
        {
            foreach(var detail in value)
            {
                detail.Master = this;
            }
            this.details = value;
        }
    }

    private IEnumerable<Detail> details { get; set; }
}

Usage:

var master = new Master
{
    Details = new List <Detail>
    {
        new Detail {}
    }
};


Console.WriteLine(
    master.Details.All(detail => detail.Master == master)
);
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84