我有兩個相關的模型
模型庫
public class ModelBase
{
public virtual ModelBase Map(DataRow dr)
{
return this;
}
}
User.cs派生自上述類。將來我希望有更多像 user 這樣的類,我可以將欄位從 DataRow 映射到我的屬性
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);
}
}
我將用戶作為DataTable接收,因此我創建了簡單的方法將其轉換為串列,但如果有更多類(均作為 DataTables 接收),我希望我的函式對我的其余模型靈活且有效。 問題是我如何動態使用它?
實用程式.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;
}
}
uj5u.com熱心網友回復:
你可以這樣做:
使ModelBase抽象和通用并使用“奇怪的重復模板模式”使您能夠定義Map()回傳派生模型型別的抽象方法:
public abstract class ModelBase<T> where T : ModelBase<T>
{
public abstract T Map(DataRow dr);
}
然后更改User為 a ModelBase<User>(Map()方法保持不變):
public class User : ModelBase<User>
{
...
}
您DataTableConverter需要有一個約束,它T是 aModelBase<T>并且有一個無引數的建構式 ( new())。該ConvertToList()方法不需要Type指定引數 - 回傳的型別由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;
}
}
正如評論中所指出的,上面的副作用是每一行都會導致創建兩個模型物件(一個在new T()被呼叫時ConvertToList(),然后該Map()方法作為映射的結果創建了一個新的模型物件。應該可以為了避免這種重復,對 AutoMapper 的使用做一個小的改變,以便它填充現有的模型物件,而不是創建一個新的物件:
public static User Map(DataRow dr)
{
...
// Populate `this` with the data row, rather than creating a new `User`
return mapper.Map(dr, this);
}
uj5u.com熱心網友回復:
@Iridium 的回答描述了如何使用 CRTP 來解決您的問題,但有一個問題,因為它Map是一個實體方法,您需要創建一個新的空User實體才能呼叫Map它,以獲得User您真正想要的實體。
如果您使用的是 C# 10(和 .NET 6),則可以使用靜態抽象介面方法。您<EnablePreviewFeatures>true</EnablePreviewFeatures>的 csproj 中可能需要(并且可能還需要<LangVersion>preview</LangVersion>)。
這讓你寫:
public interface IModelMapper<T> where T : IModelMapper<T>
{
static abstract T Map(DataRow dr);
}
public class User : IModelMapper<User>
{
public string Id { get; set; }
public string Surname { get; set; }
public string Name { get; set; }
public User() { }
public static 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);
}
}
public class DataTableConverter<T> where T : IModelMapper<T>
{
public static List<T> ConvertToList(DataTable dt, Type type)
{
var results = new List<T>(dt.Rows.Count);
foreach (DataRow row in dt.Rows)
{
results.Add(T.Map(row));
}
return results;
}
}
在dotnetfiddle.net上查看。
現在,該Map方法是靜態的:您不需要創建一個新User實體來呼叫Map它。
如果靜態抽象介面方法不可用,您可以通過分離您的關注點來獲得相同的效果(但使用更多樣板):將User類與執行映射的類分開。
public class User
{
public string Id { get; set; }
public string Surname { get; set; }
public string Name { get; set; }
public User() { }
}
public abstract class ModelMapper<T>
{
public abstract T Map(DataRow dr);
}
public class UserModelMapper : ModelMapper<User>
{
public static UserModelMapper Instance { get; } = new();
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);
}
}
然后您將 right 的一個實體傳遞ModelMapper給DataTableConverter,它是這個映射器實體進行轉換:
public static class DataTableConverter
{
public static List<T> ConvertToList<T>(ModelMapper<T> mapper, DataTable dt, Type type)
{
var results = new List<T>(dt.Rows.Count);
foreach (DataRow row in dt.Rows)
{
results.Add(mapper.Map(row));
}
return results;
}
}
在dotnetfiddle.net上查看。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/403422.html
標籤:
