Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am trying to write 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;
    }

}
like image 716
Md. Sabbir Ahamed Avatar asked Nov 10 '16 06:11

Md. Sabbir Ahamed


People also ask

How do you convert a generic list?

Select(x => new TestClass() { AAA = (string)x[0], BBB = (string)x[1], CCC = (string)x[2] }). ToList();

How do you find the type of generic type?

Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition. Get an array that contains the generic type arguments, using the GetGenericArguments method.

Can lists be generic?

You can't declare a list of generic types without knowing the generic type at compile time. You can declare a List<Field<int>> or a List<Field<double>> , but there is no other common base type for Field<int> and Field<double> than object .

Do generics prevent type cast errors?

Implementing generics into your code can greatly improve its overall quality by preventing unprecedented runtime errors involving data types and typecasting.


1 Answers

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.
like image 129
Koneke Avatar answered Oct 28 '22 13:10

Koneke