我想问一些关于映射类型和在C#中使用扩展方法的最佳实践的问题。我知道这几年来已经多次讨论过这个话题了,但是我读过很多帖子并且仍然有疑问。
我遇到的问题是使用“转换”功能扩展我拥有的类。假设我有类“Person”,它代表一些逻辑将使用的对象。我还有一个“Customer”类,表示来自外部API的响应(实际上会有多个API,因此我需要将每个API的响应映射到常见类型:Person)。我可以访问这两个类的源代码,理论上可以在那里实现我自己的方法。我需要将Customer转换为Person,以便将其保存到数据库中。该项目不使用任何自动映射器。
我有四种可能的解决方案:
.ToPerson()方法。它很简单,但它似乎打破了单一责任模式,特别是Consumer类被映射到其他类(一些需要另一个外部API),因此它需要包含多个映射方法。
在Person类中映射构造函数,将Consumer作为参数。也很容易,也似乎打破单一责任模式。我需要有多个映射构造函数(因为将有来自另一个API的类,提供与Consumer相同的数据,但格式略有不同)
带扩展方法的转换器类。这样我可以为Consumer类编写.ToPerson()方法,当用自己的NewConsumer类引入另一个API时,我可以编写另一个扩展方法并将它们保存在同一个文件中。我听说有一种观点认为扩展方法一般是邪恶的,只有在绝对必要时才能使用,这就是阻碍我的原因。否则我喜欢这个解决方案
Converter / Mapper类。我创建了一个单独的类来处理转换并实现将源类实例作为参数并返回目标类实例的方法。
总而言之,我的问题可以减少到问题的数量(所有这些都与我上面描述的相关):
将转换方法放入(POCO?)对象(如Consumer类中的.ToPerson()方法)被视为违反单一责任模式?
在(DTO-like)类中使用转换构造函数是否考虑破坏单一责任模式?特别是如果这样的类可以从多种源类型转换,那么需要多个转换构造函数吗?
在访问原始类源代码时是否使用扩展方法被视为不良做法?这种行为可以用作分离逻辑的可行模式还是反模式?
答案 0 :(得分:2)
由于这更像是一个主观的,请不要标记为答案,每个人都有自己的方式,没有任何实现是客观上最好或更好的。
1和2介绍了耦合。我不会去找他们。
对于3号,扩展方法本身违反了许多规则(至少它们在我的编程自编中制定规则)。那里有很多担忧。
在类型为System.String的类似IsValidEMail()的实例上创建扩展方法时,会发生一种静态方法,接受字符串实例作为参数。除非你反编译输出程序集,否则你当然不会看到这一点。
public static IsValidEMail(string instance);
然后,以下代码块完美无缺地运行,而不是抛出空指针异常:
string nullEMail = null;
bool isValidEMail = nullEMail.IsValidEMail();
让我不喜欢扩展方法的另一件事是Linq。
Linq包含很多扩展方法。当开发人员(特别是小辈)在IEnumerable实例上看到Count()方法时,他们可能会毫不谨慎地使用它。他们会知道这种方法在内部做什么吗?不。他们只是认为它相当于具体列表或字典对象的Count属性,并将在另一个循环内调用它,作为高级程序员,您将通过分析整个晚上的进程转储来修复生产性能问题长。
所以我打算为Linq写一个简短的口号:
Code Less, Spend More (on cpu and ram of course)
这更像是一个Linq问题然后是扩展方法的问题,但无论如何,如果IEnumerable意图有一个Count()方法,或者字符串是一个IsValidEMail方法,那么架构师会把它们放在那里而不是#39;他们?
扩展方法的另一件事。
假设你有一个代码块,编译器为丢失的方法提供了一个错误,这实际上是一个扩展方法,它位于哪个程序集和哪个类中。到目前为止,Visual Studio本身也无法告诉你。
反正。
我建议4.实际上,这被称为Mediator Pattern
我甚至建议为此目的使用一个可重复使用的映射器,他甚至不会知道你的任何类,并且仍然可以将一个映射到另一个。