C# Downcasting with generics - c#

In our project we are using .net WPF with MEF and prism.
I have to do some task and as a part of it I have different classes of Model, all implementing IModel interface (let's call them Model1, Model2, Model3).
For each model class I need to create a view model (ViewModel1, ViewModel2, ViewModel3).
I would like to do it in some generic way so it will be extensible and if tomorrow someone will implement IModel in different dll that I doesn't know about, I still will be able to create a view model for it.
I though about something like this:
[InheritedExport]
public interface IViewModelFactory<T>
{
IViewModel Create(string id, IEnumerable<IModel> modelsList);
}
public class ViewModelFactory : IViewModelFactory<Model1>
{
public IViewModel Create(string id, IEnumerable<IModel> modelsList)
{
return new ViewModel1(targetId, modelsList);;
}
}
public class FactoryLocator
{
public static IViewModelFactory<T> GetFactory<T>(T parameters)
{
return ServiceLocator.Current.GetInstance<IViewModelFactory<T>>();
}
}
And then I will use it that way:
public void CreateAndAddVM(IList<IModel> modelsList)
{
var factory = FactoryLocator.GetFactory(modelsList.FirstOrDefault());
var vm = factory.Create(_id, modelsList);
ViewModels.Add(vm);
}
When I get to the FactoryLocator, the type is actually IModel interface and not a Model1/2/3.
Is there any way to make it work somehow? Or maybe another way to implement this requirement?

You should start with interface defined like this
public interface IViewModelFactory<T> where T : IModel
{
IViewModel Create(string id, IEnumerable<T> modelsList);
}
and it will actually force correct typing on future implementers.

As I mentioned in my comment. At this moment, anyone can create a view model with a model that may not be intended for it.
For example, if your ViewModel depends on Model1, there's nothing stopping me from providing a list of Model2 to the Create method in your factory.
Consider the following:
public abstract class ViewModelBase<TModel> where TModel : IModel
The example above will allow your ViewModel to specify what Model it represents, however this goes by the assumption that a ViewModel only has one Model, which may not always be the case.
In this scenario, your ViewModelBase class should have an ID, and a Model property for the TModel.
Ensure that IModel inherits from INotifyPropertyChanged, this will allow TModel to be an ObservableCollection.

Related

How to avoid having to keep casting the argument?

I am writing a simple MVC pattern. My Views implement a simple interface.
public interface IComponentView
{
void Render(ComponentModel componentModel);
}
Here the ComponentModel is an abstract model class. Controllers are the ones responsible for preparing the new component model and call the view's Render() method while passing the new model. As you can imagine the first thing the view does inside it's own Render() function is to downcast the received parent class ComponentModel to its appropriate child class model so that all the properties and such are available for the view to use for rendering. Here is an example.
public SpecialMenuView : IComponentView
{
...
public void Render(ComponentModel componentModel)
{
SpecialMenuModel model = (SpecialMenuModel)componentModel;
// use model to render stuff
}
...
}
Is there a better way to do this rather than keep down casting for every single UI component I have?
I don't know what you're using this interface for, but if you want to transfer type information, why not generics?
public interface IComponentView<TModel> where TModel : ComponentModel
{
void Render(TModel componentModel);
}
public SpecialMenuView : IComponentView<SpecialMenuModel>
{
...
public void Render(SpecialMenuModel componentModel)
{
// use model to render stuff
}
...
}
You can make that interface contravariant for bonus points.
Not sure of an easy way to do it without generics. You can however make is nicer to follow with some pattern matching, which also takes care of ensuring the cast is fine and the model is ready to work with.
public class SpecialMenuView : IComponentView
{
public void Render(ComponentModel componentModel)
{
if (componentModel is SpecialMenuModel model)
{
// use model to render stuff
model.GetType();
}
}
}

Mapping back Viewmodels to Models

In my N-Layered DDD architectured, all my ViewModel classes in application layer, implement following interface:
public interface IViewModel
{
ModelEntitySuperType ToModel();
}
So each ViewModel knows how to map back to the Domain Object(by implementing the ToModel() method).
[Updated]
Also I used CQRS pattern in my Application layer, so I defined the following generic abstract class for implementing Update command, you can see the usage of ToModel() method in followiing class(Handle method):
public abstract class UpdateCommandHandler<TCommandParameter, TViewModel, TEntity> : ICommandHandler<TCommandParameter>
where TCommandParameter : UpdateCommandParameter<TViewModel>
where TViewModel : class, IViewModel, new()
where TEntity : ModelEntitySuperType, IAggregateRoot, new()
{
private readonly IRepository<TEntity> _repository;
public string Code { get; set; }
protected UpdateCommandHandler(IRepository<TEntity> repository, string commandCode)
{
Code = commandCode;
_repository = repository;
}
public void Handle(TCommandParameter commandParameter)
{
var viewModel = commandParameter.ViewModelEntity;
var entity = viewModel.ToModel() as TEntity;
_repository.Update(entity);
}
}
Is it a correct way, that I put mapping logic into ViewModel objects?
What is better way to achieve this goal?
Usually I have mapping logic in layer which does mapping. Thus I keep both entities and view models unaware of each other and they have single responsibility. Responsibility of mapping between data types goes to mapping library (e.g. AutoMapper) or to extension methods.
E.g. if you want to convert Person entity to PersonViewModel, then with AutoMapper it will look like
var viewModel = Mapper.Map<PersonViewModel>(person);
Or you can have extension method
public static PersonViewModel ToViewModel(this Person person)
{
// create view model and map its properties manually
}
Usage will look like your current code, except you don't need to cast ModelEntitySuperType to PersonViewModel:
var viewModel = person.ToViewModel();

C# derivative generic type arguments

I am making a web application using ASP.NET MVC 4, Entity Framework and C# and I am writing abstract superclasses to encapsulate entity models and view models. The details aren't that important though, my problem is that I want these abstract classes to implement functions to map from any given view model to a corresponding entity model and vice versa.
I actaully already implemented such methods using generics and reflection, however I want to make it more neat. I got it all working by defining the EntityModel class as such:
public abstract class EntityModel
{
public TVM MapToViewModel<TVM, TEM>()
where TVM : ViewModel<TEM>, new()
where TEM : EntityModel, new()
{ (...) }
}
It really seems unnecessary to send the type of the entity model as an argument since the calling object will know it's own type and letting the calling code specify it opens up for stupid errors but I can't figure out how get rid of it. Defining the method as
public TVM MapToViewModel<TVM>()
where TVM : ViewModel<EntityModel>, new()
seems alot neater but it gives a compile time error since EntityModel is abstract. Is there any way to tell the compiler that it must be a derivative of EntityModel but not EntityModel itself? Or is there another better solution?
The ViewModel<> class is very similar and is defined as:
public abstract class ViewModel<T>
where T : EntityModel, new()
and it is working as intended.
Consider moving the mapping functionality outside of the entity and view model classes. This will result in more appropriate separation of concerns, as well as eliminating your current generic signature issue. e.g.:
public abstract class EntityModel
{
}
public abstract class ViewModel<T>
where T : EntityModel
{
}
public class ModelMapper<TEM, TVM>
where TEM : EntityModel, new()
where TVM : ViewModel<TEM>, new()
{
public virtual TVM MapToViewModel(TEM entityModel)
{
// Default implementation using reflection.
}
public virtual TEM MapToEntityModel(TVM viewModel)
{
// Default implementation using reflection.
}
}
Nicole beat me to it... was just thinking you could have a FromEntity instead, i.e:
public abstract class ViewModel<T>
where T : EntityModel, new()
{
public static ViewModel<T> FromEntity(T entity)
{
throw new NotImplementedException();
}
}
public abstract class EntityModel
{
//... properties, methods etc...
}
Or even have the ViewModel take the EntityModel in a constructor
EDIT
As per your comment - yes you are right, I have changed the parameter to T rather than EntityModel.
The nice thing about doing it this way is that the dependency is from ViewModel > EntityModel which is the way it should be really :)

Populating collection via an interface/factory?

I am using a pattern where a concrete ViewModel implementing an interface is passed to a repository, which then populates the ViewModel object, but only using the interface. This makes for a little heavier repository, but has allowed the repository to be reused in different scenarios. For example, the concrete implementation could be a MVC ViewModel, or it could be asp.net Page that implements the interface, where the set accessor for each proeprty is actually putting the value in to the GUI, like a textbox for example. The implementation of the interface serves as the mapping and eliminates an extra step of copying. Having used AutoMapper extensively, and now being exposed to this pattern, I prefer this.
public interface IPerson
{
int Id{set};
string Name{set};
string Address{set};
}
public class PersonRepository
{
GetPerson(int id, IPerson person)
{
//query...
person.Id = result.Id;
person.Name = result.Name;
person.Address = result.Address;
}
}
//...controller action
PersonViewModel person = new PersonViewModel();
rep.GetPerson(5, person);
Here comes the tricky part though. Sometimes the ViewModel needs a collection of items, either for an Index page or for something like a drop down, or to display a nested set of child objects. The repository can't instantiate an interface, so we provide it was a factory. After fighting with covariance for awhile, I gave up on exposing any type of collection and ended up with a method that both creates and adds the collection item:
public interface IPerson
{
//...
IJobRole CreateAndAddJobRole();
}
public class PersonViewModel:IPerson
{
//collection not part of the interface
ICollection<JobRoles> JobRoles {get;set;} //= new List<JobRoles> in constructor
public CreateAndAddJobRole()
{
role = new JobRole();
JobRoles.Add(role);
return role;
}
}
public class PersonRepository
{
GetPerson(int id, IPerson person)
{
//...
foreach(var result...)
{
IJobRole role = person.CreateAndAddJobRole();
role.SomeProperty = //...
}
}
}
Obviously I'd probably have the repository that handles job roles actually be the one to populate the collection. I'd probably actual have more granular interfaces so that different repositories would be responsible for populating the data they deal with. The ViewModel would simply implement multiple interfaces. That to say, I realize there's room for improvement, but I am here specifically because I don't have any good ideas for dealing with the collection problem.
The one benefit of this design is there is no collection exposed which could be misused by the repository. There is never a guess about who is responsible for instantiating the collection itself, or who populates it, or if you had just a getter, the repository could get the collection and modify it in an invalid way. I think these would be rare occurrences because of the team would know the pattern, but it's always nice to not have pitfalls at all, instead of having pitfalls there that everyone has to remember to not step in.
As it is, it feels a little mucky.
How would you design/expose the ability for concrete types to be instantiated and added to collection, when the method doing so only has knowledge of the interfaces?
It sounds like your best bet is to make each interface generic, and pass in the types of the collections. For example:
public interface IPerson<TJob> where TJob : IJobRole
{
ICollection<TJob> JobRoles {get;set;}
void AddJobRole(TJob role);
}
public JobRole : IJobRole
{
}
public class PersonViewModel:IPerson<JobRoles>
{
//collection is now part of the interface
ICollection<JobRoles> JobRoles //= new List<JobRoles> in constructor
public void AddJobRole(JobRoles role)
{
JobRoles.Add(role);
}
}
public class PersonRepository
{
GetPerson(int id, IPerson<JobRoles> person)
{
//...
foreach(var result...)
{
person.AddJobRole(new JobRole {
SomeProperty = //...
SomeOther = //...
}
}
}
}
Of course, this assumes that you know which type of IPerson<> you want when you call GetPerson(). If you need it to handle any IPerson there, though, it becomes more problematic.

Complex User Interface -> MVC pattern

I have been reading a lot on MVC/MVP patterns.... I have a simple question....If you have a view with loads of controls....say 10 texboxes and 10 checkboxes....etc etc... Am I expected to specify the properties and events each one of them in my IView interface?....
Definitely not that way.
Your IView Interface will define set of contracts/ methods (it includes properties) that can be accessed by your business layer.
It is totally wrong to exposed your control in interface like this:
public interface IView
{
TextBox UserNameTextBox{get;set;}
}
You should not have interfaces defined in this way. This is really a bad programming.
You should rather expose some contracts that your UI layer will implement.
E.g.
public interface IView
{
public void SetUserName(string Text);
}
You can implement this interface on winform as well as webform.
Similarly, you are also not supposed to expose knowlede of UI in interface(Contract).
Lets assume a scenario where you have to display information of Employee object on UI.
You should pass Employee object to UI through this interface and UI will take care of way of representing this Employee object.
Your BL should never bother about n number of TextBoxes and checkboxes.
public class Employee
{
//first name
//last name
//is manager
//is teamleader
//address
}
public interface IEmployeeView
{
void SetEmployee(Employee employee);
}
public partial class EmployeeForm:WinForm,IEmployeeView
{
public void SetEmployee(Employee employee)
{
ENameTextBox.Text = employee.FirstName+" "+employee.LastName;
}
}

Categories

Resources