0

I currently have the following set up where I have 2 or 3 classes implementing IZoneController and I have a set of conditions determining which function they need to execute when called. I first started out defining about 20 classes for each different function, but they were really sparse, and I thought I might be able to find a better way.

Now I have my current solution, which looks like this.

public IZoneController IdentifyZone(object conditionDeterminer, IItemContainer container)
{
    Func<object, IItemContainer, List> itemAction;
    if(condition1(conditionDeterminer))
    {
        itemAction = AlterValue;
        var zController = new CCell(itemAction, container);

    }
    elseif(condition2(conditionDeterminer))
    {
        itemAction = AlterName;
        var zController = new CRange(itemAction, container);
    }

...

    elseif(condition_n(conditionDeterminer)){...}
    else(){...}
    return zController;
}

where all of my "Alter" functions have the same pattern,

List AlterValue(object toCast, IItemContainer container)
{
    return container.SetValue((decimal) toCast);
}

List AlterName(object toCast, IItemContainer container)
{
    return container.SetName((string) toCast);
}

...

List AlterX(object toCast, IItemContainer container)
{
    return container.SetX((xType) toCast);
}

Now here's the big question. I was wondering if there is a way write a single function where I can define what method I want to call from the IItemContainer interface, as well as what type I want to cast the object to. It would look something like,

Func<object, IItemContainer, List> CreateItemAction<T>(Func<T, List> containerFunction)
{
}

I'm not exactly sure how it would actually be called, but maybe something like

delegate List itemAlteration = IItemContainer.SetX;
itemAction = CreateItemAction<xType>(itemAlteration);

or

delegate List itemAlteration = container.SetX;
itemAction = CreateItemAction<xType>(itemAlteration);

And I just can't figure out what should go into the guts of the CreateItemAction function to make it actually work. Any observations, requests for more information, or pointers on where and why this code is poorly structured would be greatly appreciated.

As a side note, I get the sense that all of the casting from object to string/decimal is pretty smelly, but it's user input, and at some point I'll implement some handling of bad inputs. Should I just move the cast part into the actual classes that implement IItemContainer?

  • 1
    Your explnation is only about code not about the big picture where it would be used, that code make me imagine some sort of generic for all solution to handle form event, or editing in a grid events. Usually to handle that you use listeners. Aniway, eventually you could have a FilterAction interface with two method : match and execute. You move the condition in the match method and the code to execute in the execute method. Your IdentifyZone is just a loop against all configured FilterAction. It's better but I still don't really like that. – Walfrat Oct 3 '17 at 14:50
  • You're right about the big picture, this code is called by a listener when a change event occurs on a grid, and the conditionDeterminer is an object which holds information about which zone of the grid the change occurred on. After the listener calls IdentifyZone, it performs List newList = zController.Execute(newValue) which returns a list of changes that are used to update different pieces of information on the grid. I could move the conditionDeterminer logic to a match function in each class that implements FilterAction, but I'm not sure where to go from there. – Daniel Shank Oct 3 '17 at 15:19
  • Basically with that grid, you can't associate an editing controller to a column, you're forced to do it by cell right ? I think it would be better if you would handle that yourself then : having a map of Column/ItemAction, and then from the event, just compute from which column the event occur. Of course that's only works is your data is always of the same kind in the same column for all rows. – Walfrat Oct 4 '17 at 7:22
  • Can't you make your specific implementations of IZoneController generic? EG: CCell<int>(container, action>; where the action will be a Setter of int (Func<int, IItemContainer, List>. Another question: from where your controllers receive the value that will be passed to the setters (your Alter functions)? – Emerson Cardoso Oct 4 '17 at 12:47
0

Think about getting rid of the interface and simply using delegates. The function to be executed must be specified by name when you create the delegate. You don't need anything more than naming the function and passing it to a storage object that has a generic type parameter for the function parameter. I say get rid of the interface as then it serves no purpose, delegates are equivalent. You could use a Delegate (non-generic) as the storage object, and reflection to determine what type of parameter, but I think it is best to create a storage class with a type parameter.

A better solution would be to get rid of both the interface and the delegates, and use an event. That would be in line with the framework design guidelines.

|improve this answer|||||
  • If you could go into more detail about what using events would look like, that'd be great. I ended up using delegates in the CCell class public delegate List ActionChainCreator(object toCast, IItemContainer item) and then lambda functions like itemAction = ((toCast, container) => container.SetValue((decimal) toCast). I still needed to keep the interface, since there's still some slight differences in behavior that occur depending on which zone the change action was triggered from. – Daniel Shank Oct 4 '17 at 12:49
  • @DanielShank That's exactly what I was thinking of. For the event example, I made a mistake. I confused the listener aspect with the delegate aspect. They are separate. Which brings up another point. I don't truly understand why you need the delegates at all (i.e. the big picture was not clear). I only understood enough of the last part of the question to formulate an answer. I do get the feeling that if you do need delegates, you might be better off going the other way, i.e. supplying functions to the thing that contains cells. I just get the feeling there is some unnecessary complexity here. – Frank Hileman Oct 4 '17 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.