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;
}
}
Select(x => new TestClass() { AAA = (string)x[0], BBB = (string)x[1], CCC = (string)x[2] }). ToList();
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.
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 .
Implementing generics into your code can greatly improve its overall quality by preventing unprecedented runtime errors involving data types and typecasting.
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
Using Activator to create an instance, like this
entities = list.ConvertAll(x => (TVm)Activator.CreateInstance(typeof(TVm), x));
or
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.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With