我是否认为需要像AutoMapper这样的东西表明设计不佳是错误的吗?


35

Automapper是.Net的“对象-对象映射器”,这意味着将对象从一个类复制到另一个表示相同事物的类中。

为什么这会有用?类的重复是否曾经有用/良好的设计?


一些参考资料:devtrends.co.uk/blog/…特别是阅读“为什么我们不能使用自动映射器”一节。
JaniHyytiäinen2014年

Answers:


28

快速的Google搜索显示了以下示例:

http://www.codeproject.com/Articles/61629/AutoMapper

显示了AutoMapper的完全有效用法,这绝对不是不良设计的示例。在分层应用程序中,您可能在数据或业务层中有对象,有时您只需要该数据对象的属性的子集,或者在UI层中需要它们的某种视图。因此,您将创建一个视图模型,其中包含的对象完全具有您UI中所需的属性,而没有更多,并使用AutoMapper以更少的样板代码为这些对象提供内容。

在这种情况下,您的“视图对象”不是原始类的副本。他们有不同的方法,也许有一些重复的属性。但这没关系,只要您仅将该视图对象用于UI显示目的,并且不要开始将其用于数据操作或业务操作即可。

为了更好地理解这一点,您可能会读到的另一个主题是Fowlers Command Query Responsibility Segregation模式,与CRUD相反。它向您展示了在其中查询数据并在数据库中更新它们的不同对象模型有意义的情况。在这里,从一个对象模型到另一个对象模型的映射也可以通过AutoMapper之类的工具完成。


1
关于第一个示例:您不能组成对象而不是复制它们吗?在这种情况下,您的UI对象将引用原始数据对象,并且仅公开必要的元素。那没有道理吗?
static_rtti 2012年

1
@static_rtti理论上可以,但是您不一定希望您的原始班级是公开的或/或在程序
集中

2
@static_rtti:是的,这是一种完全有效的不同方法。这两种设计之间的主要区别是数据/属性的寿命。使用副本可为您提供数据快照,而使用引用原始数据的属性则不会。两种方法都有其优点和缺点,但是恕我直言,总体上没有“更好或更坏”的说法。此外,可能会有性能方面的考虑,这些影响可能会也可能不会影响使用什么的决策。
布朗

3
尽可能去耦始终是一个好主意。不是因为它甚至对小型项目都特别有利,而是因为项目会不断增长。
陶Szelei

6
@fish:我大都同意,去耦通常是个好主意,但是恕我直言,在很多情况下,保持简单比解耦的多层超级解耦方法更为重要。困难的部分是不要错过一个项目的成长过程中应该开始重构的地步。
布朗

45

类的重复是否曾经有用/良好的设计?

优良作法是在UI层中使用单独的视图模型类,而不要在数据层中使用相同的类。您的UI /网页可能需要显示与数据实体不严格相关的其他信息。通过创建此额外的类,您可以随需随时间变化,从而自由地轻松调整UI。

就使用AutoMapper而言,出于以下三个原因,我个人避免使用它:

静默故障更常见

因为AutoMapper自动在属性之间映射,所以更改一个类而不是另一个类的属性名称将导致跳过属性映射。编译器不会知道。Automapper不会在乎。

缺乏静态分析

因此,您已经获得了处理大量代码的基础。有100万个类别和100万个属性。看起来好像它们没有被使用,或者是重复的。Visual Studio中的“查找所有引用”工具将帮助您查看使用属性的位置,并帮助您在整个应用程序如何将其挂在一起的过程中构建映射。但是,等等,因为使用了Automapper,所以没有显式引用属性的一半。我的工作现在变得更加艰难。

后期要求增加了复杂性

当您要做的只是将值从一个类复制到另一个类时(通常在开发开始时就是如此),Automapper既好又花哨,但是还记得那些随时间变化的需求吗?如果现在需要从应用程序的其他部分获取值,可能是特定于已登录用户或某些其他上下文状态,该怎么办?

AutoMapper在应用程序启动时创建一对一类映射的模式不适用于这些类型的特定于上下文的更改。是的,可能有使其工作的方法,但是我通常会发现自己编写逻辑更简洁,更简单且更具表现力。

总之,在寻求Automapper节省30秒的手动将一个类映射到另一个类之前,请考虑一下这一点。

编程是一种告诉他人要计算机做什么的艺术。-唐纳德​​·努斯

考虑到这一点,请问自己“ AutoMapper在今天有帮助,明天会有用吗?”


[如果您是时髦的Web开发人员]那么,如果您正在编写REST Web服务,您倾向于总是检查每个属性以确保您的JavaScript对象模型与.NET对象模型一致吗?
2014年

3
@Den-是的 然后编写测试以确保所有属性正确(即,测试将显示您在1个地方添加的任何属性,这些属性不会传播到其他层)
gbjbaanb 2014年

@gbjbaanb我可能只会使用反射以一般方式进行此验证。也许探索扩展AutoMapper来添加一些验证的可能性。肯定会避免大量的手动分配。
2014年

完全同意您的看法,并认为只有非常简单的应用程序才能使用自动映射器,但是当事情变得更加复杂时,我们需要为自动映射器编写新的配置,那么为什么不在手动映射器帮助程序或服务中编写这些配置。
ahmedsafan86

21

以我的经验,当有人抱怨“样板太多”并想使用AutoMapper时,它就是以下之一:

  1. 他们发现一遍又一遍地编写相同的代码很烦人。
  2. 他们很懒,不想编写执行Ax = Bx的代码
  3. 他们承受着太多的时间压力,无法真正考虑一遍又一遍地编写Ax = Bx是否是一个好主意,然后为该任务编写好的代码。

然而:

  1. 如果确实要避免重复,则可以创建一个对象或方法来抽象它。您不需要AutoMapper。
  2. 如果您很懒,那么您将很懒,并且不会学习AutoMapper的工作方式。取而代之的是,您将采用“巧合编程”模式,并在将业务逻辑填充到AutoMapper配置文件中的地方编写可怕的代码。在这种情况下,您应该改变对编程的态度,或者另谋高就。您不需要AutoMapper。
  3. 如果您承受太多的时间压力,则问题与编程本身无关。您不需要AutoMapper。

如果您选择了静态类型的语言,请利用该语言。如果您试图绕过使用该语言的控件,以防止由于过度使用反射和魔术API(如AutoMapper)而导致的错误,那仅表示您选择的语言不能满足您的需求。

另外,仅因为Microsoft在C#中添加了功能并不意味着它们在每种情况下都是公平的游戏,也不意味着它们支持最佳实践。例如,如果您没有它们就无法完成所需的工作,则应使用反射和'dynamic'关键字。AutoMapper并不是无法解决所有用例的解决方案。

那么,重复类是否设计不好?不必要。

AutoMapper是个坏主意吗?是的,一点没错。

使用AutoMapper表示项目中存在系统缺陷。如果您发现自己需要它,请停下来考虑您的设计。您将始终找到更好,更易读,更可维护且更无错误的设计。


1
得好

2
我知道这是一个非常老的线程,但是我不同意1。您无法创建抽象映射的方法。您可以为1个类,但如果有2个,则需要2个方法。3-3种方法。对于AM,这是1行代码-映射的定义。另外,我真的在一个场景中挣扎,我有一个List <BaseType>填充了10个DTO子类型。当您想要映射它时,您需要打开类型和复制字段值的方法。如果必须单独映射一个字段怎么办?仅当您只有几个简单的课程时,您的答案才是好的。在更复杂的情况下,AutoMapper胜出。
user3512524 '18

1
(字符数限制)我认为AM的唯一陷阱是可以更改一个类而不是另一个类的属性名称。但是,实际上,在设计完成之后,您多久这样做一次?您可以编写一个使用反射并比较属性名称的通用测试方法。像所有工具一样,AM必须正确使用-我同意,不要盲目地,不是在所有情况下都可以使用AM。但是说“你不应该使用它”是错误的。
user3512524

7

这里有一个更深层次的问题:C#和Java坚持大多数/所有类型必须通过名称而不是结构来区分的事实:例如class MyPoint2Dclass YourPoint2D即使它们具有完全相同的定义,它们也是单独的类型。当您想要的类型是“一些带有x字段和y字段的匿名事物”(即record)时,您很不走运。因此,当您想要将a YourPoint2D变成a时MyPoint2D,您有三个选择:

  1. 按照以下方式写一些乏味,重复,平凡的样板 this.x = that.x; this.y = that.y
  2. 以某种方式生成代码。
  3. 使用反射。

小剂量的选择1很容易,但是当您需要映射的类型数量很大时,选择1很快就会变得很麻烦。

选择2不太理想,因为现在您必须在构建过程中添加额外的步骤来生成代码,并确保整个团队都能得到备忘录。在最坏的情况下,您也必须滚动自己的代码生成器或模板系统。

那让你沉思。您可以自己做,也可以使用AutoMapper。


2

Automapper是皇帝从头到尾裸奔的那些库/工具之一。当您摆脱耀眼的徽标时,您会意识到它无法执行您无法手动执行的任何操作,并且效果更好。

虽然我不太确定它如何暗示自动映射成员,但它很可能涉及其他运行时逻辑和可能的反射。为了节省时间,这可能是重大的性能损失。手动映射,另一方面,提示在编译时间之前就已执行。

如果AutoMapper没有任何线索,则必须使用代码和设置标志配置映射。如果您要花时间完成所有设置和代码工作,则必须质疑它比手动映射节省了多少。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.