我遇到了一个非常简单的问题,我找不到简单的解决方案。我正在寻找一种优雅的模式来在两个数据源之间映射数据
来源A 来源B
A1 类 -> B1 类
A2 类 -> B2 类
A3 类 -> B3 类
等
我有一些带有重载方法的静态类,用于在类之间映射数据:
public static class Mapper{
public static ClassB1 Map(ClassA1){
return new ClassB1();
}
public static ClassB2 Map(ClassA2){
return new ClassB2();
}
// etc.
}
我想要一些简单的模式以通用风格工作,比如
public void ProcessEntity<TA, TB>(string EntityNameInSourceA, string EntityNameInSourceB){
List<TA> dataA = Source1.GetData<TA>(EntityNameInSourceA);
List<TB> dataB = Mapper.Map(dataA);
Source2.SaveData<TB>(dataB);
}
并使用它
public void Main(){
ProcessEntity<ClassA1, ClassB1>("TableA1", "TableB1");
ProcessEntity<ClassA2, ClassB2>("TableA2", "TableB2");
ProcessEntity<ClassA3, ClassB3>("TableA3", "TableB3");
}
这样我就可以通过修改 Mapper 类并添加新行来简单地添加一对新的类
ProcessEntity<ClassA4, ClassB4>("TableA4", "TableB4");
问题是我不能在泛型方法中使用这个Mapper.Map,因为它需要在编译时指定类。
嗯,我可以
if (typeof(TA) == typeof(ClassA1)){
ClassB1 dataB = Mapper.Map(dataA)
}
尽管如此,我相信我从一开始就做错了,并且存在一些美丽的解决方案。有什么想法吗?
请注意,您的示例混合了单个实例和类列表,但由于其伪代码,我假设这只是一个错误。
从根本上来说,你想要“双重调度”,即选择的函数取决于 2 个参数的类型。
在 C# 中执行此操作的一种方法是使用
dynamic
(这是完整的运行时调度)。如果您将调用映射器的参数转换为(动态),那么要使用哪个映射器函数的“选择”将在运行时而不是编译时确定。
缺点是,如果您忘记将正确的项目添加到映射器,则可能会出现运行时类型错误,就像任何使用动态的东西一样。
如果您可以控制 ClassA1 类型项目,您可以通过回调来实现,即
public interface IMappable<TOutput> //Possible with some type resritcions so you get some ancestior type for you 'B' classes
{
TOutput Map();
}
public interface ISaveable //Possible with some type resritcions so you get some ancestior type for you 'B' classes
{
public void SaveTo(Source Source);
}
public static class Mapper{ //You can move this logic directly INTO A if approriate
public static ClassB1 Map(ClassA1 from){
return new ClassB1();
}
public static ClassB2 Map(ClassA2 from){
return new ClassB2();
}
}
public class ClassB1 : ISaveable { public void SaveTo(Source source) { source.SaveData(this); } }
public class ClassB2 : ISaveable { public void SaveTo(Source source) { source.SaveData(this); } }
public class ClassA1 : IMappable<ClassB1> //This is your fundemental type mapping
{
public ClassB1 Map() => Mapper.Map(this);
}
public class ClassA2 : IMappable<ClassB2> //This is your fundemental type mapping
{
public ClassB2 Map() => Mapper.Map(this);
}
你的来电者看起来像这样(暂时忽略你列出的东西):
void ProcessEntity<TA>(string EntityNameInSourceA, string EntityNameInSourceB) where TA: IMappable<ISaveable>
{
TA dataA = Source1.GetData<TA>(EntityNameInSourceA);
ISaveable dataB = dataA.Map();
dataB.SaveTo(Source2);
}
为什么? 很重要的是,该语言允许“单一调度”,您可以创建一个子类并重写一个方法,这样您就可以仅根据一种类型更改行为(选择的函数)。 通过让此类进行第二次调用,您将获得另一个允许重写的点,从而允许双重调度。