tengo dos modelos relacionados
ModelBase.cs
public class ModelBase { public virtual ModelBase Map(DataRow dr) { return this; } }User.cs que se deriva de la clase anterior. En el futuro, quiero tener más clases como usuario donde pueda asignar campos de DataRow a mis propiedades.
public class User : ModelBase { public string Id { get; set; } public string Surname { get; set; } public string Name { get; set; } public User() { } public override User Map(DataRow dr) { var config = new MapperConfiguration (cfg => cfg.CreateMap<DataRow, User>() .ForMember(dest => dest.Id, opt => opt.MapFrom(row => row["x"])) .ForMember(dest => dest.Name, opt => opt.MapFrom(row => row["xx"])) .ForMember(dest => dest.Surname, opt => opt.MapFrom(row => row["xxx"])) ); var mapper = config.CreateMapper(); return mapper.Map<User>(dr); } }Recibo Usuarios como DataTable , por lo que he creado un método simple para convertirlo en una lista, pero si habrá más clases (todas recibidas como DataTables), quiero que mi función sea flexible y válida con el resto de mis modelos. La pregunta es ¿cómo puedo usar esto dinámicamente?
Utilidad.cs
public class DataTableConverter<T> where T : ModelBase { public static List<T> ConvertToList(DataTable dt, Type type) { var results = new List<T>(dt.Rows.Count); foreach (DataRow row in dt.Rows) { // Here I want to call Map function from dynamic model and add it to results } return results; } }Podrías hacer algo como esto:
Haga ModelBase abstracto y genérico y use el "Patrón de plantilla curiosamente recurrente" para permitirle definir un método Map() abstracto que devuelva los tipos de modelos derivados:
public abstract class ModelBase<T> where T : ModelBase<T> { public abstract T Map(DataRow dr); } Luego cambie User para que sea un ModelBase<User> (el método Map() permanece sin cambios):
public class User : ModelBase<User> { ... } Su DataTableConverter debe tener una restricción de que T es un ModelBase<T> y tiene un constructor sin parámetros ( new() ). El método ConvertToList() no requiere que se especifique un parámetro Type ; el tipo devuelto está determinado por T :
public class DataTableConverter<T> where T : ModelBase<T>, new() { public static List<T> ConvertToList(DataTable dt) { var results = new List<T>(dt.Rows.Count); foreach (DataRow row in dt.Rows) { results.Add(new T().Map(row)); } return results; } } Como se señaló en los comentarios, el efecto secundario de lo anterior es que cada fila da como resultado la creación de dos objetos modelo (uno cuando se llama al new T() en ConvertToList() , y luego el método Map() crea un nuevo objeto modelo como un resultado de la asignación Debería ser posible evitar esta duplicación con un pequeño cambio en el uso de AutoMapper para que rellene el objeto modelo existente, en lugar de crear un nuevo objeto:
public static User Map(DataRow dr) { ... // Populate `this` with the data row, rather than creating a new `User` return mapper.Map(dr, this); }