[英]Strongly Typed Type Parameters
出於性能原因,我不能使用Automapper或任何其他基於約定的映射工具。 理想情況下,我想要一個可以調用的方法簽名...例如-mapper.Map <,>()但是以下語法無效
public MyModelView Map<Tin, Tout>(Tin source)
where Tin: MyModelDto
where Tout: MyModelView
{
return new MyModelView{
Prop1 = source.Prop1;
};
}
public MyModelDto Map<Tin, Tout>(Tin source)
where Tin: MyModelView
where Tout: MyModelDto
{
return new MyModelDto {
Prop1 = source.Prop1;
};
}
以下是一種可行的解決方案,但我個人覺得很丑。
public void Map(MyModelDto source, out MyModelView outParam)
{
outParam = new MyModelView();
outParam.Prop1 = source.Prop1;
}
public void Map(MyModelView source, out MyModelDto outParam)
{
outParam = new MyModelDto ();
outParam.Prop1 = source.Prop1;
}
MyModelDto myDto = new MyModelDto { Prop1 = "Hello World" };
MyModelView myView;
mapper.Map(myDto, out myView);
我的問題是,有沒有辦法在不使用反射的情況下強制使用確定類型,或者使用out參數來強制唯一性,或者out param方法是我將要獲得的最干凈的方法?
更新:因此,我制定了一個滿足我需要的解決方案,它利用了RuntimeTypeHandle,雖然它並不完全理想,但它對我有用,並且使用起來最少的麻煩。 如果我的要求僅允許每個對象進行1個類型轉換,那么我將堅持使用一個更簡單的解決方案。 為了完整性...這是我想出的。
歸因於類型處理的想法: 什么更快,打開字符串或其他類型的輸入?
public class Mapper : IMapper
{
private delegate object TypeHandler(Object node, Type desiredReturn);
private static readonly Dictionary<RuntimeTypeHandle, TypeHandler> TypeLibrary = CreateTypeHandler();
private static Dictionary<RuntimeTypeHandle, TypeHandler> CreateTypeHandler()
{
var ret = new Dictionary<RuntimeTypeHandle, TypeHandler>();
ret[typeof(MyModelDto).TypeHandle] = HandleMyModelDto;
//ret[typeof (Jill).TypeHandle] = HandleJill;
//ret[typeof (Marko).TypeHandle] = HandleMarko;
return ret;
}
private static object HandleMyModelDto(object source, Type desiredMapping)
{
MyModelDto sourceObj = source as MyModelDto;
if (desiredMapping == typeof(MyModelView))
{
return new MyModelView { Prop1 = sourceObj.Prop1 };
}
else if (desiredMapping == typeof (MyModelBusiness))
{
return new MyModelBusiness { Prop1 = sourceObj.Prop1 };
}
}
public Tout Map<Tin, Tout>(Tin source)
{
TypeHandler handler;
if (TypeLibrary.TryGetValue(Type.GetTypeHandle(source), out handler))
{
return (Tout)handler(source, typeof(Tout));
}
else
{
//Unexpected type...
throw new NotImplementedException("Type mapping not implemented");
}
}
}
消費如下
Mapper mapper = new Mapper();
MyModelDto myDto = new MyModelDto { Prop1 = "Hello World" };
MyModelView returnVal = mapper.Map<MyModelDto, MyModelView>(myDto);
不幸的是,在C#中,您不能定義具有相同簽名(即相同的方法名稱+參數)的兩個方法來返回兩種不同的類型,但是,例如,如果您的視圖和dto對象實現了一個公共接口,則類似於以下內容:
public interface IMyModel
{
string Prop1 { get; set; }
}
然后,您可以按以下方式定義Map方法:
public Tout Map<Tin, Tout>(Tin source)
where Tin: IMyModel
where Tout: IMyModel, new()
{
var result = new Tout();
result.Prop1 = source.Prop1;
return result;
}
然后可以將其稱為:
var view = Map<MyModelDto, MyModelView>(dtoInstance);
var dto = Map<MyModelView, MyModelDto>(viewInstance);
如果您知道涉及的類型和成員,為什么要嘗試使Map通用? 忘記“ Tin
和“ Tout
,只使用您接受/返回的基本類型。
public MyModelView Map(MyModelDto source)
{
return new MyModelView{
Prop1 = source.Prop1
};
}
基於MyModelDto
任何內容MyModelDto
必須具有Prop1
並且基於MyModelView
任何內容MyModelView
必須具有Prop1
。 即使它是任一子類的子類,也要在不進行反思的情況下使用它,則必須在基類中定義這些成員。 如果每個子類都有變體,例如額外的成員,則需要為每個合法的轉換創建映射器函數的自定義版本(實際上,不要使用類繼承,因為這樣做只會增加復雜性,在此沒有任何好處)。 這將是最快的代碼,但要以維護映射例程為代價。
僅當您僅需要將MyModelDto映射到另一種對象類型時,這才起作用。 假設我要將dto保存到我的數據庫對象層或其他視圖模型中。 我將無法創建唯一的方法簽名,因為C#不會將返回類型視為唯一的方法簽名的一部分
那么你也能:
public void Map(MyModelDto source, out MyModelView target)
{
target = new MyModelView {
Prop1 = source.Prop1
};
}
但我寧願建議你不要這樣做,因為有工作out
PARAMS可以是惱人。 相反,請使用MapToView
, MapToModel
等或保留Map
但要通過不同的命名空間(對於擴展方法,可能是最佳選擇)或靜態類名(執行MapView.Convert()
和MapModel.Convert()
MapView.Convert()
MapModel.Convert()
。 命名空間可能是最好的策略,因為在我看來,在大多數代碼部分中,您將只處理一個版本或另一個版本,而不是兩個版本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.