views:

180

answers:

2

I have a control and it provides a selection mechanism. However, the items that it selects are not appropriate for general consumption and instead, must be projected into a different type parameterised by date.

In addition to this, there are some controls that want to encapsulate the same information and, more importantly, want to retain a particular selection even if the original control's selection has changed. Therefore, just chaining methods doesn't work because the original control's method will always return the projection of its current selection.

To work around this, I created a property that returns a closure, which performs the projection based on a specific selection. This way, I can encapsulate the projection and protect the real type being projected, but also encapsulate a specific collection. Here is a simplified version of what I have.

public class MySelectionControl
{
  public Func<DateTime, IEnumerable<MyProjectedType>> CreateSelectionForDate
  {
    get
    {
       // Take a copy of the selection before creating the lambda so
       // that the source items won't change if the selection does.
       IEnumerable<MyRealType> copyOfSelection = this.realSelection.ToList();
       return weekEnding =>
          copyOfSelection.Select(x => new MyProjectedType(x, weekEnding));
    }
  }
}

This can then be called like a method as in:

MySelectionControl control = new MySelectionControl();

// Gives the current selection for a given date.
control.CreateSelectionForDate(DateTime.Today);

// Takes a copy of the selection for later use, regardless of
// whether the original selection changes.
var selectedItemsProjection = control.CreateSelectionForDate;

So, is this terrible design or clever use of delegates?

+1  A: 

I think it is pretty clever. The only thing I would do would be to turn your property (CreateSelectionForDate) into a method as that (for me anyways) would make the code clearer.

Andrew Hare
The main reason I didn't make it a method is that then you would call it as: control.CreateSelectionForDate()(DateTime.Today). Note the double set of parentheses.
Jeff Yates
Ah - good point.
Andrew Hare
I think it really depends on whether you'll use it more like a method or more like a property as to which is better, right?
Jeff Yates
My opinion is that a property generally encapsulates a field whereas a method generally does not. In the end they are both methods anyways. My only thought was that the use of a property tends to imply a less expensive call than the use of a method.
Andrew Hare
I agree. However, this is unlike most situations I've come across. It's an unusual hybrid propod or metherty. :)
Jeff Yates
+2  A: 

Since the purpose of this arrangement is to provide a context and a method to run from within that context, it would seem better to use it more like this:

Closure closure = selectionControl.GetClosure(DateTime.Today);
closure.DateSelection ...
John Fisher
I see your point though I'm not sure the closure.DateSelection makes sense in this context. Can you explain that part?
Jeff Yates
The DateSelection property would return the selection information, equivalent to running the delegate in the code you posted.
John Fisher
Ah yes, I see your point. Perhaps CreateClosure would be a closer fit (matter of opinion, though) but I see what you're getting at. It does make the intentions clearer and should make the code more maintainable.
Jeff Yates