c# - switch/case on viewmodel in controller, refactoring advice highly appreciated -
i use advice on refactoring. in application users able dynamically add new form fields; customfield. each type (text, dropdown, checkbox, etc.) viewmodel (textboxviewmodel, dropdownviewmodel, checkboxviewmodel, etc.) defined.
when post form, appropriate edit action executed , read each customfield store values.
currently implementation works ugly; switch/case/if/else through viewmodel types , based on type execute required logic.
this the current implementation:
private static void maptomodel(ticket ticket, ticketviewmodel model) { ticket.id = model.id; ticket.name = model.name; ticket.attributes.clear(); foreach (var cvm in model.controls) { var attribute = new ticketattribute { id = cvm.id, name = cvm.name, }; if (cvm textboxviewmodel) { attribute.value = ((textboxviewmodel) cvm).value; }else if (cvm dropdownlistviewmodel) { attribute.value = ((dropdownlistviewmodel)cvm).values; } ticket.attributes.add(attribute); } }
and refactor this, without putting logic in viewmodel. best come visitor pattern add accept method viewmodel class, , use visitors execute logic required:
this still require same switching logic on types in addattribute method:
foreach (var cvm in model.controls) { ticket.attributes.addattribute(cvm); }
this require logic in viewmodel class
foreach (var cvm in model.controls) { ticket.attributes.add(cvm.addattribute); }
i want refactor create more generic approach, in future when new types of fields added don't have update codes new constructions check types.
[solution afer provided help]
i had cast object, cannot use different returntypes in different implementations of icontrolviewmodel 1 part have work around, overall beautiful.
ticket.attributes = model.controls .oftype<icontrolviewmodel>() .select(cvm => new ticketattribute { id = cvm.id, name = cvm.name, value = (string)cvm.outputvalue }) .tolist(); public interface icontrolviewmodel { string id { get; } string name { get; } object outputvalue { get; } } public abstract class controlviewmodel : icontrolviewmodel { public string id { get; set; } public abstract string type { get; } public string label { get; set; } public string name { get; set; } public bool visible { get; set; } public abstract object outputvalue { get; } } public class textboxviewmodel : controlviewmodel { public override string type { { return "textbox"; } } public override object outputvalue { { return value; } } public string value {set; } }
1) create interface defines have output value property on each of view models
public interface icontrolviewmodel { object outputvalue{get;} }
2) implement interface in each of viewmodels:
public textboxviewmodel: icontrolviewmodel { ... public object outputvalue { { //return whatever expected output value control return value; } } ... }
3) can attributes single linq statement:
ticket.attributes = model.controls .oftype<icontrolviewmodel>() .select(cvm => new ticketattribute { id = cvm.id, name = cvm.name, value = cvm.outputvalue }) .tolist();
4) code work fine if create new control types, make sure implement interface in new viewmodels.
Comments
Post a Comment