0

I have a tree constructed using a TreeNode class where each node has an Amounts object. The Amounts object is a simple class that houses some decimal values. E.g.

public class Amounts
{
    public decimal Amount1 { get; set; }
    public decimal Amount2 { get; set; }
    ...
}

I need to be able to perform some code for each individual property independently, and what I'd like to do is somehow pass one of the Amounts properties to this method using a lambda or similar but I can't quite work out how to do this (I've been a while off the tools unfortunately). I don't particularly like the idea of passing a property name string so I can use reflection SetPropertyValue method.

I want the traversal method to look something like the below. I'm aware that Linq supports a Sum method but I have just used this as a simplified example, with the actual calculation performed being more complex.

public void Traverse(Func<ContributionAmounts, decimal> getter)
{
    foreach (var child in this.Children)
    {
        getter(this.Amounts) += getter(child.Amounts);
    }
}

Rather than having a separate method for each amount, I'd like to do be able to call it something like below:

Traverse(a => a.Amount1);
Traverse(a => a.Amount2);

The code above does not work as the value returned by the Func is a read-only decimal value, rather than the decimal property (e.g. Amount1).

I'm not sure if I have explained the requirement very well, but hopefully enough to get a pointer in the right direction.

Thanks, John

John
  • 605
  • 2
  • 7
  • 17
  • Given the lambda, all you have to do is apply it to each item in your collection. LINQ includes a `Sum()` method, so it's as simple as `this.Amounts.Amount1 += this.Children.Sum(a => a.Amounts.Amount1);`. There doesn't appear to be a need for your `Traverse()` method. – Peter Duniho Oct 25 '17 at 07:10
  • Thanks for the response. It seems that I oversimplified the example so I have updated it to clarify. The question isn't so much about summing the child values, but how to specify which amount to sum. Hopefully the updated example clears this up. – John Oct 27 '17 at 03:44
  • I don't see why you need `Traverse()` or a way to set the property. It's just the property of the current instance, so the code I posted in my previous comment should work fine. – Peter Duniho Oct 27 '17 at 04:54
  • That said, if you insist: you will have to pass both a `getter` and `setter` argument, where the latter is something like `Action` or `Action`, and the lambda looks like `d => this.Amounts.Amount1 += d` or `(ca, d) => ca.Amounts.Amount1 += d`. I.e. basically the same as the marked duplicate, but with a setter delegate as well. Since even in the latter case, `ca` is known by the caller, I don't see why you'd need that version. And since you don't need that version, you shouldn't need `Traverse()` at all. – Peter Duniho Oct 27 '17 at 04:54

1 Answers1

0
public void Traverse(Func<Amounts, decimal> getter)
{
    var a = new Amounts();
    decimal result = getter(a);
}

//...

Traverse(t => t.Amount1);
Traverse(t => t.Amount2);
Backs
  • 24,430
  • 5
  • 58
  • 85
  • Thanks for the response. This is close to what I'm looking for, but I need to be able to set the property rather than just retrieve it (see updated example above). Cheers – John Oct 27 '17 at 03:45