【问题标题】:Can this be simplified in C#?这可以在 C# 中简化吗?
【发布时间】:2016-10-06 14:53:52
【问题描述】:

我有一些重复的代码,但不确定简化它的最佳方法。

private void CheckData(long PKID, int ExpectedResult, string Server)
{
    var a = _ARepo.GetAll();
    var b = _BRepo.GetAll();

    if(Server == "A")
    {
        a.Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
    }

    if (Server == "B")
    {
        b.Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
    }
}

这是一个单元测试项目,我正在使用Shouldly 库。任何想法表示赞赏。

【问题讨论】:

  • ab有哪些类型?
  • (Server == "A" ? a : b).Find(...) 我想。或者只是引入一个变量并为其分配 a 或 b,具体取决于 Server。然后在这个变量上查询 Find。
  • @GiladGreen 它们是使用 Repository 模式的同一类型,Dapper 从 SQL Server 数据库中获取数据。
  • 在进行任何检查之前,从 Repo A 或 Repo B 获取数据不是更好吗?您只需要在此处获取大量数据。
  • 与其节省代码行,不如只访问一个存储库而不是两个存储库来提高性能。

标签: c# c#-5.0 code-duplication


【解决方案1】:
private void CheckData(long PKID, int ExpectedResult, string Server)
{
    //Setting to empty because I don't know what happens if it is not "A" nor "B"
    IEnumerable<YourType> data = Enumerable.Empty<YourType>();

    if(Server == "A")
        data = _ARepo.GetAll();
    else if(Server == "B")
        data = _BRepo.GetAll();

    data.Find(Find(x => x.PKID == PKID).Result.ShouldBe(expectedId);
}

如果Server 值只能是AB,那么您可以用if else 或更好的?: 运算符替换 然后它看起来像:

var data = Server == "A" ? _ARepo.GetAll() : _BRepo.GetAll();
data.Find(Find(x => x.PKID == PKID).Result.ShouldBe(expectedId);

在两个Repos 实现相同接口的情况下,更好的设计是将IRepo 作为函数的参数。这样该函数只有一个角色——检查数据(而不是决定检查哪些数据)

【讨论】:

  • 很有帮助,我按照你的建议把方法改成了private void CheckData(long PKID, int ExpectedResult, Repository repo)
  • @MarkAllison - 很高兴帮助 :) 顺便说一句 - 如果已经编写 UT 并更好地负责代码段,那么我建议使用 IRepository 而不是具体的 Repository :) 查看SOLID - 写代码和创作艺术有点不同 :)
【解决方案2】:

您可以制作一个辅助方法来处理这种重复:

private void CheckFind<T>(List<T> a, int expectedId) where T : IWithId {
    a.Find(x => x.PKID == PKID).Result.ShouldBe(expectedId);
}

CheckData调用此方法两次:

if(Server == "A") {
    CheckFind(_ARepo.GetAll(), ExpectedResultId);
}
if(Server == "B") {
    CheckFind(_BRepo.GetAll(), ExpectedResultId);
}

【讨论】:

  • @Evk 是的。但是,分配单个变量需要两种类型相同,而我的方法可以很容易地调整为泛型类型列表,并带有用于获取 ID 的接口。
  • @Servy 如果您可以使用IEnumerable&lt;T&gt;,这将是正确的。但是,Find 的使用表明 OP 使用 List&lt;T&gt;,所以不,你的把戏是行不通的。
【解决方案3】:

如果所有 Repos 都实现相同的接口(如 IRepo)。你可以像这样创建一个辅助方法

    private IRepo GetRepo(string server)
    {
        var repos = new Dictionary<string, IRepo>
        {
            { "A", _ARepo },
            { "B", _BRepo }
        };

        return repos[server];
    }

使用很简单

    private void CheckData(long PKID, int ExpectedResultId, string Server)
    {
        var repo = GetRepo(Server);
        repo.GetAll().Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
    }

【讨论】:

    【解决方案4】:

    是的,如果你可以重构你的代码并且你的 _ARepo.GeAll_BRepo.getAll 在返回的类型中实现相同的接口,这将类似于以下内容

    private void CheckData(long PKID, int ExpectedResult, string Server, IRepo repo)
    {
        var b = repo.GetAll();  
        b.Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
    }
    

    【讨论】:

      【解决方案5】:

      使用一些简短的 if 表示法,您可以使用以下内容 假设_ARepo和_BRepo来自同一个类但连接字符串不同

      private void CheckData(long PKID, int ExpectedResult, string Server)
      {
         BaseType repo = Server == "A" ? _ARepo : _BRepo;
         repo.GetAll().Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
      }
      

      假设它们不是同一个 BaseType 但 GetAll() 是 IEnumerable

      private void CheckData(long PKID, int ExpectedResult, string Server)
      {
         IEnumerable<YourType> repo = Server == "A" ? _ARepo.GetAll() : _BRepo.GetAll();
         repo.Find(x => x.PKID == PKID).Result.ShouldBe(ExpectedResultId);
      }
      

      【讨论】:

      • 如果 _ARepo 和 _BRepo 之间没有隐式转换,则不能将隐式 var 与条件运算符一起使用
      • 注意到了,但是很容易假设 _(x)Repo 与 Type 相同,如果您只看代码的结构方式,并且连接字符串只会服务器'A'和服务器'B'不同但是我已经更新了我的答案以涵盖它是否相同以及是否不同
      猜你喜欢
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 2022-08-08
      • 1970-01-01
      • 1970-01-01
      • 2021-06-23
      • 2020-11-21
      • 2017-07-01
      相关资源
      最近更新 更多