Func<>;或测试代码中的方法

本文关键字:代码 方法 测试 lt gt Func | 更新日期: 2023-09-27 18:09:32

我在测试代码中看到了这个循环:

foreach ( StuffId Id in Result.GetIdList() )
{
    if ( Id.Level == 3 )
    {
        Level3Id = Id.ToString();
    }
    if ( Id.Level == 5 )
    {
        Level5Id = Id.ToString();
    }
}

其他测试表明,每个级别只有一个Id,或者当每个级别有多个Id时,Id将是相同的。

由于现在有点痴迷于LINQ,我首先重构为:

IEnumerable<StuffId> Ids = Result.GetIdList();
Level3Id = Ids.Where( x => x.Level == 3 ).First().Id.ToString();
Level5Id = Ids.Where( x => x.Level == 5 ).First().Id.ToString();

然后代码重复困扰着我,所以我重构为:

IEnumerable<StuffId> Ids = Result.GetIdList();
Func<int,string> IdFromLevel = 
    level => Ids.Where( x => x.Level == level ).First().Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);

一位同事想知道我为什么不使用方法来代替委托。我的理由是,一个方法会稍微"混乱"一些,因为我必须额外传递集合,并且使用委托对于简单的测试来说没什么大不了的(简洁、可读和无分支是很好的品质(。

当然,我查看了SO,发现了一个看似相关的问题:

C#:函数<>而不是方法?

共识似乎倾向于一种方法而不是一个代表。这同样适用于我的情况吗?

Func<>;或测试代码中的方法

这是一个重用问题。如果您使用的方法在其他情况下可能是可重用的,则应该单独定义它们
但是,如果您只有另外变化的简短语句,则应该坚持使用匿名函数/lambda表达式,这可能会导致更好的运行时行为。

来自SO:

你发布的代码没有任何优势。在代码中,使用委托只会增加复杂性和额外的运行时成本,因此最好直接调用该方法。

但是,代理有很多用途。"传递"给其他方法是主要用途,尽管存储一个函数并稍后使用它也非常有用。

LINQ完全建立在这个概念之上。当你这样做:

var results = myCollection.Where(item => item == "Foo");

您正在将一个委托(定义为lambda:item=>item=="Foo"(传递给LINQ库中的Where函数。这就是它正常工作的原因。

不确定利弊,但阅读这些文章可能会帮助您做出更好的决定:

http://msdn.microsoft.com/en-in/library/bb549151.aspx

http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx

http://msdn.microsoft.com/en-in/library/98dc08ac.aspx

我会选择第一个块:

foreach (StuffId Id in Result.GetIdList())
{
    if (Id.Level == 3)
    {
        Level3Id = Id.ToString();
    }
    if (Id.Level == 5)
    {
        Level5Id = Id.ToString();
    }
}

这只会循环集合一次。我知道你在这里并不担心性能,但对我来说,这不是性能或优化的问题。这是一个以逻辑正确的方式做事的问题。如果某件事可以在一个步骤中完成,为什么要做两次呢(前提是可读性不受影响(。

额外的好处是,您不会在Func<,>和方法以及相关的复杂性之间左右为难。就字符数量或打字方便性而言,它几乎是一样的,只是你是水平写的(在第二种情况下(而不是垂直写的。您甚至可以在foreach块内的两行中写入上述内容。

如果你想分别写这两个动作,我会根据函数是否在当前方法范围之外的相关性来做出选择。在我看来,这是一个微不足道的谓词,只与两个赋值有关。所以我喜欢:

var Ids = Result.GetIdList();
Func<int, string> IdFromLevel = level => Ids.Single(x => x.Level == level).Id.ToString();
Level3Id = IdFromLevel(3);
Level5Id = IdFromLevel(5);

这里更喜欢Single而不是First。。