65.9K
CodeProject 正在变化。 阅读更多。
Home

代码简化!!

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.05/5 (8投票s)

2012 年 7 月 18 日

CPOL

3分钟阅读

viewsIcon

27082

本文重点介绍如何利用 .NET 的现有功能来提高代码的可维护性,从而降低圈复杂度并减少代码行数。

引言

如今,任何软件实现都在与外部或内部系统(例如,SOA)通信,存在大量实体、大量代码,当然也有大量映射。 本文重点介绍如何利用 .NET 的现有功能来提高代码的可维护性,从而降低圈复杂度并减少代码行数。

背景

几天前,我正在实现一个新功能,发现在现有代码中,使用大量实体,并且只有一对一的映射却需要大量的代码。 我运行了代码度量(来自 VS 2010),发现代码不可维护。 如果这段代码对于我这样一个开发人员来说都很难阅读和理解,那么以后维护它的人呢?

这促使我搜索了一些小的调整来提高代码质量。

代码之美

在编写代码时,有很多简单的方法(我们通常会忘记或忽略)可以使我们的代码看起来美观且易于维护。

  1. 内联初始化

所以,不要这样:

PersonalInfo entity = new PersonalInfo();
AddressEntity nameAndAddress = new AddressEntity();
nameAndAddress.DayPhone = Convert.ToString(orderEntity.dely_phone_day);
nameAndAddress.EveningPhone = Convert.ToString(orderEntity.dely_phone_eve);
nameAndAddress.AddressLine1 = orderEntity.dely_address1;
nameAndAddress.AddressLine2 = orderEntity.dely_address2;
nameAndAddress.AddressLine3 = orderEntity.dely_address3;
nameAndAddress.AddressLine4 = orderEntity.dely_address4;
nameAndAddress.AddressLine5 = orderEntity.dely_address5;
nameAndAddress.ZipCode = orderEntity.Postcode;
nameAndAddress.FirstName = orderEntity.NickName;
nameAndAddress.Title = orderEntity.dely_address_no.ToString();
entity.Address = nameAndAddress;

我们可以这样写:

AddressEntity nameAndAddress = new AddressEntity()
{
    DayPhone = Convert.ToString(orderEntity.dely_phone_day),
    EveningPhone = Convert.ToString(orderEntity.dely_phone_eve),
    AddressLine1 = orderEntity.dely_address1,
    AddressLine2 = orderEntity.dely_address2,
    AddressLine3 = orderEntity.dely_address3,
    AddressLine4 = orderEntity.dely_address4,
    AddressLine5 = orderEntity.dely_address5,
    ZipCode = orderEntity.Postcode,
    FirstName = orderEntity.NickName,
    Title = orderEntity.dely_address_no.ToString()
}; 

通过这种方式,您可以实现:

  • 更好的可读性
  • 更好的可维护性
  • 在计算代码度量时,这将被视为一行。 因此,这将减少代码行数(对于此示例,从 13 行代码减少到 1 行)
  • 将防止重复赋值(对于具有大量属性的实体,这将非常有用)
  • 更快地编码

2. 映射函数

当进行一对一映射时,我们首先做什么? 我们编写一个方法,类似于这样

public static MyEntity MapServiceEntityToMyEntity(ServiceEntity response) 

这就是它的调用方式

ServiceEntity response = GetServiceResponse(params); 
MyEntity entity = Mapper.MapToMyEntity(response);  

mapper 类逐渐增长。

当有多个开发人员在同一段代码上工作,而你的一个同事在实现一个新功能时,无法正确找到这个函数并决定编写他自己的映射方法时,就会出现问题。 类似于这样

public static  MyEntity MapToMyEntity(ServiceEntity response) 

接下来发生了什么? 代码编译通过,映射也起作用。 但是这增加了代码行数,它有重复的代码,并且最重要的是,维护这段代码的人会祈祷你死

我们能做些什么呢? 始终记住一件事。 当你将类型 "A" 转换为类型 "B" 时,你的映射类/方法应该始终只有一个函数来完成此操作。 我们可以通过创建扩展方法来确保这一点。 我们也可以就命名约定达成一致。

我选择重载名为 "Map" 的所有函数。 因此,我的 "Mapper.cs" 包含所有名为 "Map" 的方法。 下面是一个例子。

 public static MyEntity Map(this ServiceEntity response)  

通过这种方式,您可以实现:

  • 防止映射函数的重复
  • 易于编码
ServiceEntity response = GetServiceResponse(params);
MyEntity entity = response.Map();  

您可以让它更容易

MyEntity entity = GetServiceResponse(params).Map();

  • 减少代码行数
3. 映射列表 [本节需要 LINQ 和 PLinq 的知识]

当我们映射一个列表时,我看到很多人这样做:

List<AddressEntity> listOfAddresses = new List<AddressEntity>();
foreach (ServiceResponse serviceAddress in response)
{
    AddressEntity address = new AddressEntity();
    address.DayPhone = serviceAddress.DayPhone;
    address.EveningPhone = serviceAddress.EveningPhone;
    address.HouseNumber = serviceAddress.HouseNo;
    address.Road = serviceAddress.Road;
    address.City = serviceAddress.City;
    address.Country = serviceAddress.Country;
    address.ZIpCOde = serviceAddress.ZipCode;
    listOfAddresses.Add(address);
}

我们可以通过使用 Linq 来直接改进这一点

List<AddressEntity> listOfAddresses = 
  new List<AddressEntity>(response.Select<ServiceResponse,AddressEntity>(serviceAddress =>
                new AddressEntity()
{
    DayPhone = serviceAddress.DayPhone,
    EveningPhone = serviceAddress.EveningPhone,
    HouseNumber = serviceAddress.HouseNo,
    Road = serviceAddress.Road,
    City = serviceAddress.City,
    Country = serviceAddress.Country,
    ZipCOde = serviceAddress.ZipCode
}));

如果内部映射需要一些繁重的操作(例如计算总数或检查属性),并且您不关心列表中元素的顺序,则可以进一步使用并行 Linq 或 PLinq(请记住 - 确保在并行循环下使用的操作/变量/方法都是线程安全的)

List<AddressEntity> listOfAddresses = 
  new List<AddressEntity>(response.AsParallel().Select<ServiceResponse,AddressEntity>(serviceAddress =>
new AddressEntity()
{
    DayPhone = serviceAddress.DayPhone,
    EveningPhone = serviceAddress.EveningPhone,
    HouseNumber = serviceAddress.HouseNo,
    Road = serviceAddress.Road,
    City = serviceAddress.City,
    Country = serviceAddress.Country,
    ZipCOde = serviceAddress.ZipCode
}));

有关并行编程的更多信息 - http://msdn.microsoft.com/en-us/library/ff963553

当你以这种方式重构你的代码时,确保性能完好无损。 虽然这超出了本文的范围,但我建议对循环进行一些性能调整,并为特定逻辑使用最佳选项(for、foreach、Linq、Plinq、Parallel for 和 foreach)。

一个好的链接是 - https://codeproject.org.cn/Articles/6759/FOREACH-Vs-FOR-C

另一个非常有用的链接 - http://geekswithblogs.net/BlackRabbitCoder/archive/2010/08/26/c.net-five-little-wonders-that-make-code-better-1-of.aspx

 

 

© . All rights reserved.