How to convert a generic data type to another generic data type

I am trying to write a Generic Base Service Class , which after receiving the first list of data as the actual Db Model Entity type needs to be converted to a new general data type .

I tried list.ConvertAll() , but always got a build error for the ConvertAll() method.

I also tried list.Cast<TVm>().ToList() to solve this problem, but get a runtime error.

Here are my code snippets of all classes and interfaces. Any help or suggestion appreciated.

Entity class

 public abstract class Entity { [Key] [Index("IX_Id", 1, IsUnique = true)] public string Id { get; set; } [DataType(DataType.DateTime)] public DateTime Created { get; set; } public string CreatedBy { get; set; } [DataType(DataType.DateTime)] public DateTime Modified { get; set; } public string ModifiedBy { get; set; } [DefaultValue(true)] public bool Active { get; set; } } 

BaseViewModel Class

 public abstract class BaseViewModel<T> where T: Entity { protected BaseViewModel() { } protected BaseViewModel(T model) { Id = model.Id; Created = model.Created; CreatedBy = model.CreatedBy; Modified = model.Modified; ModifiedBy = model.ModifiedBy; Active = model.Active; } public string Id { get; set; } public DateTime Created { get; set; } public string CreatedBy { get; set; } public DateTime Modified { get; set; } public string ModifiedBy { get; set; } public bool Active { get; set; } } 

IBaseService Interface

 public interface IBaseService<T, TVm> where T : Entity where TVm : BaseViewModel<T> { List<TVm> GetAll(); } 

BaseService class

 public abstract class BaseService<TEntity, TVm> : IBaseService<TEntity, TVm> where TEntity: Entity where TVm : BaseViewModel<TEntity> { protected IBaseRepository<TEntity> Repository; protected BaseService(IBaseRepository<TEntity> repository) { Repository = repository; } public virtual List<TVm> GetAll() { List<TVm> entities; try { List<TEntity> list = Repository.GetAll().ToList(); entities = list.Cast<TVm>().ToList(); //runtime error entities = list.ConvertAll(x => new TVm(x)); //build error entities = list.ConvertAll(new Converter<TEntity, TVm>(TEntity)); //build error } catch (Exception exception) { throw new Exception(exception.Message); } return entities; } } 
+6
source share
2 answers

To create an instance of a generic type, you need new() -constraint. However, this does not allow you to pass any parameters. You can try either

  • Using an activator to create an instance, for example

    entities = list.ConvertAll(x => (TVm)Activator.CreateInstance(typeof(TVm), x));

or

  1. Add new() -constraint to TVm in the signature of the BaseService class and add the method to the classes that you pass to it as TVm , which basically does what the current constructor does, but in the method, and call it after creating a new object.
+2
source

I think the best option you have tried is entities = list.ConvertAll(x => new TVm(x)); . The reason it cannot be compiled is because classes with C # inheritance do not have to have the same constructor as the base class. Instead, you should initialize TVm inside the BaseService . In addition, your try catch does nothing but lose some data and affects StackTrace , so it's best to delete it. Below code should work for you.

 public abstract class BaseService<TEntity, TVm> : IBaseService<TEntity, TVm> where TEntity: Entity where TVm : BaseViewModel<TEntity>, new() { protected IBaseRepository<TEntity> Repository; protected BaseService(IBaseRepository<TEntity> repository) { Repository = repository; } private TVm ConvertToViewModel(TEntity model) { return new TVm { Id = model.Id, Created = model.Created, CreatedBy = model.CreatedBy, Modified = model.Modified, ModifiedBy = model.ModifiedBy, Active = model.Active, }; } public virtual List<TVm> GetAll() { List<TEntity> list = Repository.GetAll().ToList(); List<TVm> entities = list.ConvertAll(x => ConvertToViewModel(x)); return entities; } } 
0
source

Source: https://habr.com/ru/post/1012198/


All Articles