Home > Software engineering >  Trying to set up Nested Object in C#, with computed field based on list
Trying to set up Nested Object in C#, with computed field based on list

Time:02-03

I am experimenting with a nested object class for an upcoming software project, in C#. I know how to do computed fields/properties within a class, at least as far as setting it programmatically with something like the date.

This is a little different. I am setting up a nested class like this:

string Test { get; set; }

List<Line> Detail { get; set; }

decimal Total { 
  get {
    return TotalOf();
  }
}

decimal TotalOf() {
  var listQuery = this.Detail;

  // This is where I'm trying to figure out how to do.  
  // I want the TotalOf function to return the sum of the  
  // Cost fields of  the contained list items (Line is defined below).  
  // I will remove the "return 0;" eventually once 
  // I can figure out how to do the calculation.
            
     return 0;
}

public class Line {
  int indexOf { get; set; }
  decimal Cost { get; set; }
}

That way, the field Total is automatically calculated rather than me having to compute it through the code consuming this class.

I have tried searching all over but I can't seem to find the right answer. I have plenty of time to do this, and worst case, I can just do it in the program consuming this class, but I thought I'd ask. When I hit the . after typing in this.Detail, the only aggregate function that comes up is Count.

I have tried to use the Detail.Sum function, hoping the Linq would bring up a lambda expression that I could then say "add up the Cost" but it won't come up.

I know this should be simple but I can't figure it out.

CodePudding user response:

Think this method would work for you:

decimal TotalOf() {
    return this.Detail.Select(line => line.Cost).Sum();
}

I believe this way also works:

decimal TotalOf() {
    return this.Detail.Sum(line => line.Cost);
}

Hope this helps :)

CodePudding user response:

First, set access modifiers for Line properties like as public or other. Because, on default state it is private.

public class Line
{
  public int indexOf { get; set; }
  public decimal Cost { get; set; }
}

Then, set up root class like as LineCollection.

public class LineCollection
{
  public class Line
  {
    public int indexOf { get; set; }
    public decimal Cost { get; set; }
  }

  public string Test { get; set; }
  public List<Line> Detail { get; set; }
  public decimal Total { get; set; }
}

On LineCollection initialize default values for properties on constructor:

public class LineCollection
{
  public class Line
  {
    public int indexOf { get; set; }
    public decimal Cost { get; set; }
  }

  public string Test { get; set; }
  public List<Line> Detail { get; set; }
  public decimal Total { get; set; }

  public LineCollection() 
  {
    this.Test = string.Empty;
    this.Detail = new List<Line>();
  }
}

After this modify get/set accessors for Total property. I guess, property is read only and we not need to define set accessor.

public decimal Total
{
  get
  {
    return this.Detail.Sum(x => x.Cost);
  }
}

Code in get accessor automatically runs when we trying to get his value. Finally, we can run tests for checks.

LineCollection collection = new LineCollection();
collection.Detail.Add(new LineCollection.Line() { indexOf = 0, Cost = 43.3m });
collection.Detail.Add(new LineCollection.Line() { indexOf = 1, Cost = 23 });
collection.Detail.Add(new LineCollection.Line() { indexOf = 3, Cost = 56.21m });
Console.WriteLine(collection.Total.ToString());

It returns 122,51.

  • Related