Md. Sabbir Ahamed Md. Sabbir Ahamed - 1 month ago 19
C# Question

How to Convert a generic type list of data to another generic type list of data

I am trying writing a Generic Base Service Class where after receiving the fist generic list of data as the actual type of Db Model Entity need a conversion to a new Generic View Model type of data.

I have tried

list.ConvertAll()
but always getting a build error for
ConvertAll()
method.

I also tried
list.Cast<TVm>().ToList()
this solve the build error but getting the run time error.

Here are my code snips of all classes and interfaces. Any help or suggestion is 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;
}

}

Answer

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

  1. Using Activator to create an instance, like this

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

or

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