I'm using a view model first approach and in some models I expose other models via an interface like this:
public class ModelA : IModel {}
public class ModelB : IModel {}
// plus yet unknown additional models
public class ViewModelA : IViewModel
{
ViewModelA(ModelA model){}
}
// a model may have several possible view models that should be selectable somehow
public class ViewModelAVariant : IViewModel
{
ViewModelAVariant(ModelA model){}
}
public class ViewModelB : IViewModel {}
{
ViewModelA(ModelB model){}
}
public class ModelContainer
{
public IModel[] SubModels { get { return new IModel { new ModelA(), new ModelB()};}}
}
public class ViewModelContainer
{
private ModelContainer modelContainer;
public IViewModel[] SubModels
{
get
{
return modelContainer.SubModels.Select( sm => ToViewModel(sm)).ToArray();
}
}
private IViewModel ToViewModel(IModel model)
{
// what to insert here?
}
}
Possible solutions
Variant 1:
Store a collection of IModel
to IViewModel
converters and use them in the ViewModel.
private IDictionary<type,Func<IModel,IViewModel>> converters;
private IViewModel ToViewModel(IModel model)
{
return converters[model.GetType()](model);
}
Pros:
- The model does not have to know about the view models
- It's possible to select a ViewModels
Cons:
- The process may fail at runtime if there is no suitable converter
Variant 2:
interface IModel
{
IViewModel ToViewModel();
}
public class ModelA : IModel
{
// this enables view model selection
public ModelA(Func<ModelA,IViewModel> converter)
{
this.converter = converter;
}
private Func<ModelA,IViewModel> converter;
public IViewModel ToViewModel()
{
return converter(this);
}
}
Pros:
- It's possible to select a ViewModels
- easy to use, hard to misuse
Cons:
- The model has to know about the view models
I'm looking for a variant without the drawbacks.
Sounds like a good use case for AutoMapper.
Basically you would create a configuration, in it's simplest case it's:
This assumes that all properties are named same (in both ViewModel and Model). It can also flatten properties, i.e.
ModelA.Property
is mapped, by convention toModelAProperty
if it exists.If you have more complex mappings, you have to configure the mappings.
Then resolve it via
and for variations:
You shouldn't use it the other way though, at least it's not recommended to convert from ViewModel to Domain/Business Model. It's main goal is for Model to DTO (Data Transfer Objects) or Model to ViewModel mappings.