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 :)
Related
So I'm trying to store an object with a generic type that inherits from a base abstract class. Bellow are the some class definition.
public abstract class BaseModel<T> {
//dose some serialization things for building a save file
}
public abstract class StatusEffectLogicModel<T> : BaseModel<StatusEffectLogicModel<T>{
//dose some delegate and event things
}
//Actual implementations of the Status Effect model
public class TauntStatusEffectLogic : StatusEffectLogicModel<TauntStatusEffectLogic> {
//Dose Taunt Specific things
}
public class RallyStatusEffectLogic : StatusEffectLogicModel<RallyStatusEffectLogic> {
//Dose Rally Specific things
}
//Where I'm having issues
public class CharacterModel : BaseModel<CharacterModel> {
//this is what I need Help with how can i have a property that is of an unknown generic
public StatusEffectLogicModel activeStatusEffect;
}
The closest solution i think i've found is to use a dynamic property but I'm not sure i fully grasp the implications of using this, is this really the best way to achieve what I'm looking for? I'm open to other solutions.
We have an interface to deal with DAL with pretty simple definition:
interface IRepository<T> : IQueriable<T> // so we can read data from database
{
Save(T document); // dozen of methods here
}
Mostly we use two implementations: real version and in memory version for unit testing. Here is declarations of one of class:
public RealRepository : IRepository<AccountEntity> { ... }
// typical IOC usage
services.AddSingleton<IRepository<AccountEntity>, RealRepository<AccountEntity>>();
Now we are working to spin off for main codebase to custom version of project and we need custom fields in data and occassional custom behavior in repository. Most of classes are fine with base implementation but others would require specific implementation. So my goal is to get to following services in:
var repository = new RealRepository<CustomAccountEntity>();
services.AddSingleton(IRepository<AccountEntity>, repository);
// for new classes
services.AddSingleton(IRepository<CustomAccountEntity>, repository);
I tried to add out T to IRepository but I am using T in input parameters and this gave compile time "Invalid variance" error.
I can see a solution by adding second type parameter to interface so it looks like:
IRepository<TBase, out TChild> : IQueriable<TChild> {
Save (T document);
}
Finally, Question: How can make change 100% backward compatible?
What I tried:
Add IRepository<T>: IRepository<T,T> -> complies, but RealRepository is not implementing IRepository anymore.
Add 2 interfaces in implementation: public class RealRepository<TBase, TChild>: IRepository<TBase, TChild>, IRepository<TChild> but this gives compliation error 'cannot implement both ... and ... because they may unify for some type parameter substitutions'
Save(T document) has T in a contravariant position. That means in T, not out T.
Let's recap what contravariance means. Suppose you had this code:
using System;
public class Entity {}
public class AccountEntity : Entity {}
public class CustomAccountEntity : AccountEntity {}
public interface IQueryable<in T>
where T : Entity
{}
public interface IRepository<in T>
where T : Entity
{
void Save(T record);
}
public class EntityRepository<T> : IRepository<T>
where T : Entity
{
public void Save(T record) {}
}
public class Program
{
public static void Main()
{
// This is ***VALID***:
IRepository<CustomAccountEntity> repo = new EntityRepository<AccountEntity>();
Console.WriteLine(repo == null ? "cast is invalid" : "cast is valid");
}
}
https://dotnetfiddle.net/cnEdcm
So whenever you need a IRepository<CustomAccountEntity>, you can use a concrete EntityRepository<AccountEntity> instance. Seems counter-intuitive, but it's actually totally right: If the concrete method is Save(AccountEntity), it can obviously handle CustomAccountEntity instances too; OTOH if the concrete method were Save(CustomAccountEntity), it would NOT be able to handle simple AccountEntity instances.
Having said that, then I think you should
Use contravariance instead;
Declare all dependencies using the most specialised type, e.g. IRepository<CustomWhateverEntity>;
In the IoC registration code, for each particular entity, setup either Repository<CustomeWhateverEntity>, if you need the extra behaviour, or just Repository<WhateverEntity> otherwise.
I'm working on a project in C# 4.0. I have several presenter classes, which all inherit from the same base class. Each of these presenter classes has a "current" object, which is specific to each presenter, but they all also have a common inherited class, separate from the presenters, of course.
In terrible pseudo-code:
class ApplicationPresenter inherits BasePresenter
Pubilc PersonApplication Current (inherited from Person)
class RecordPresenter inherits BasePresenter
Public PersonRecord Current (inherited from Person)
class InquiryPresenter inherits BasePresenter
Public PersonInquiry Current (inherited from Person)
...etc
Is there a way to make it so I can call "current" from any of these, without requiring type detection, but keep it in line with best practices?
The best option I have I think is to just make it a dynamic, as I know whatever I pass to it will have "current" and do it that way. Is that proper?
Or is there a way that I could create:
class BasePresenter
Public Person Current
And make that cast appropriately?
I know there are ways around this, but I'm looking for clean and proper, for once.
Thank you!
Add generic type parameter to a base presenter so any derived concrete presenter would be able specifying custom Current item type:
public abstract class PresenterBase<TItem>
{
public TItem Current { get; private set; }
}
// now Current will be of PersonApplication type
public sealed class ApplicationPresenter : PresenterBase<PersonApplication>
{
}
// now Current will be of PersonRecord type
public sealed class RecordPresenter : PresenterBase<PersonRecord>
{
}
Well, I've had to rewrite this as I've been down voted five times for giving too much detail... Go figure!
class BaseModel
{
public T[] Get<T>()
{
// return array of T's
}
public T Find<T>(object param)
{
// return T based on param
}
public T New<T>()
{
// return a new instance of T
}
}
class BaseRow
{
private BaseModel _model;
public BaseRow(SqlDataReader rdr, BaseModel model)
{
// populate properties of inheriting type using rdr column values
}
public void Save()
{
// calls _model.Save(this);
}
}
I currently have a number of classes that inherit the BaseModel class. Each of the methods exposed by BaseModel will return an instance, or an array of instances of a type that inherits the BaseRow class.
At the moment, when calling the exposed methods on the BaseModel via an inheriting class, i.e.
using(DeviceModel model = new DeviceModel())
{
DeviceRow row = model.Find<DeviceRow>(1);
DeviceRow[] rows = model.Get<DeviceRow>();
DeviceRow newRow = model.New<DeviceRow>();
}
I have to specify the type (a class that inherits the BaseRow class), as the methods in BaseModel/BaseRow do not know/care what type they are, other than they inherit from BaseRow.
What I would like to do is find a way to remove the need to specify the without having to replicate code in every class that inherits BaseModel, i.e.
class DeviceModel : BaseModel
{
public DeviceRow Find(object param)
{
return this.Find<DeviceRow>(param);
}
}
Note: Unfortunately I am unable to implement or use any third party solutions. That said, I have tried using Castle Active Record/nHibernate and to be honest, they are very big and heavy for what should be a very simple system.
Hopefully I haven't provided "too much" detail. If I have, please let me know.
Thanks
If I were you, I'd suggest making BaseModel a generic class. In a situation of "can't win either way", the code you've removed to make others happy might have told me more about what you're doing (not a criticism by any stretch - I appreciate your position).
class BaseModel<T>
{
public virtual T[] Get()
{
// return array of T's
}
public virtual T Find(object param)
{
// return T based on param
}
public virtual T New()
{
// return a new instance of T
}
}
That's your base, and then you have inheritors like:
class DeviceModel : BaseModel<Device>
{
public override Device New()
{
return new Device();
}
}
Now, any generic operations you define in DeviceModel will default to returning or using strongly typed Device. Notice the virtual methods in the BaseModel class. In the base class methods, you might provide some basic operations predicated upon using T's or something. In sub-classes, you can define more specific, strongly typed behavior.
I'd also comment that you might want to pull back a little and consider the relationship of BaseModel and BaseRow. It appears that you're defining a parallel inheritance hierarchy, which can tend to be a code smell (this is where more of your code might have come in handy -- I could be wrong about how you're using this). If your ongoing development prospects are that you're going to need to add a FooRow every time you add a FooModel, that's often a bad sign.
I want to implement a generic method to retrieve header/detail data from a database:
public static T RetrieveHeaderDetail<T>
where T : Header<???>, new()
// Where ??? means "what can I do here?"
{
// ...
}
Here is the definition of the generic representing a document header:
public class Header<TDetail> where TDetail : class, new()
{
public List<TDetail> Details;
}
And here are some instantiations:
public class RequestForQuotation : Header<RequestForQuotationDetail> { ... }
public class Order : Header<OrderDetail> { ... }
public class Invoice : Header<InvoiceDetail> { ... }
// ..
It is not hard to prove that, since .NET does not allow either multiple inheritance or "generic specialization" (which would allow a Header<U> to derive from some other Header<V>), for any specific T, there is at most one U such that T inherits (directly or indirectly) from Header<U>. Moreover, it is trivial to find the type U: iterate over T's base types until you find an instance of Header<U>, and then just take the generic's argument! Still, C# wants me to specify the change my method's definition to the following:
public static T RetrieveHeaderDetail<T,U>
where T : Header<U>, new()
where U : class, new()
{
// ...
}
Is there any way to get around this problem? I know it would be possible using Reflection, but I think it is a good practice to never do at runtime what could be done at compile time.
When I hit problems like this, I really, really miss C++.
I asked this question not too long ago.
Generics with Generic Parameters and Abstract class
I'm not sure I fully understand what you're after, but could you define an interface and use it to specify the constraint?
For example, we have something like this in a couple places:
public class Reader<T> where T : IInt32Id
{
public T GetById(int Id)
{
// get by id
}
}
Then I just use IInt32Id as an interface to derive all of my classes that have an int (as opposed to long) ID field.