Question

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.

Était-ce utile?

La solution 2

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 :)

Autres conseils

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.
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top