建站技术

当前位置:

.NET中*延迟*特性的几个陷阱

浏览量:

 .NET发展至今,其实各处都有“延迟(Lazy)”的痕迹,一个小小的“Laziness”给我们带来了不少灵活性。“延迟”的关键就在于“只在需要的时候处理数据”,老赵曾经在多篇文章中提到了类似的概念,如《高阶函数、委托与匿名方法》及《您善于使用匿名函数吗?》。不过“延迟”本身也会给您带来一些陷阱,某些陷阱您很有可能也曾经遇到过。这篇文章便是总结了延迟特性的集中常见陷阱,并给出应对方案。

  .NET发展至今,其实各处都有“延迟(Lazy)”的痕迹,一个小小的“Laziness”给我们带来了不少灵活性。“延迟”的关键就在于“只在需要的时候处理数据”,老赵曾经在多篇文章中提到了类似的概念,如《高阶函数、委托与匿名方法》及《您善于使用匿名函数吗?》。不过“延迟”本身也会给您带来一些陷阱,某些陷阱您很有可能也曾经遇到过。这篇文章便是总结了延迟特性的集中常见陷阱,并给出应对方案。

  重复运算

  问题

  “延迟”的本意是“减少计算”,但是如果您使用不当,很可能反而会造成“重复计算”。例如,我们首先构建一个方法,它接受一个参数n,返回一个Func对象:

 


 static Func DivideBy(int n)
  {
  return x =>
  {
  bool divisible = x % n == 0;
  Console.WriteLine(
  "{0} can be divisible by {1}? {2}",
  x, n, divisible ? "Yes" : "No");
  return divisible;
  };
  }

 

  返回的Func对象会根据传入的参数x,返回一个表示x能否被n整除的布尔值。在这过程中,还会向控制台输出一句话,例如:“10 can be divisible by 3? No”。每当看到这句话,则表明“经过了一次判断”。那么您是否知道,下面的代码会输出什么结果呢?

 


   List values = new List();
  for (int i = 0; i < 10; i++) values.Add(i);
  var divideByTwo = values.Where(DivideBy(2));
  var divideByTwoAndThree = divideByTwo.Where(DivideBy(3));
  var divideByTwoAndFive = divideByTwo.Where(DivideBy(5));
  foreach (var i in divideByTwoAndThree) { }
  foreach (var i in divideByTwoAndFive) { }

 

  结果如下:

 


      0 can be divisible by 2? Yes
  0 can be divisible by 3? Yes
  1 can be divisible by 2? No
  2 can be divisible by 2? Yes
  2 can be divisible by 3? No
  3 can be divisible by 2? No
  4 can be divisible by 2? Yes
  4 can be divisible by 3? No
  5 can be divisible by 2? No
  6 can be divisible by 2? Yes
  6 can be divisible by 3? Yes
  7 can be divisible by 2? No
  8 can be divisible by 2? Yes
  8 can be divisible by 3? No
  9 can be divisible by 2? No
  0 can be divisible by 2? Yes
  0 can be divisible by 5? Yes
  1 can be divisible by 2? No
  2 can be divisible by 2? Yes
  2 can be divisible by 5? No
  3 can be divisible by 2? No
  4 can be divisible by 2? Yes
  4 can be divisible by 5? No
  5 can be divisible by 2? No
  6 can be divisible by 2? Yes
  6 can be divisible by 5? No
  7 can be divisible by 2? No
  8 can be divisible by 2? Yes
  8 can be divisible by 5? No
  9 can be divisible by 2? No

 

  您是否发现,无论是在遍历divideByTwoAndThree和divideByTwoAndFive序列时,都会从原有的values序列里重新判断每个元素是否能够被2整除?这就是.NET 3.5中“Where”的延迟特性,如果您在这里没有意识到这点,就可能会产生重复计算,浪费了计算能力。

  解决方案

  解决这个问题的方法就是在合适的时候进行“强制计算”。例如:

 


 var divideByTwo = values.Where(DivideBy(2)).ToList();
  var divideByTwoAndThree = divideByTwo.Where(DivideBy(3));
  var divideByTwoAndFive = divideByTwo.Where(DivideBy(5));

 

  结果就变成了:

 


  0 can be 


[声明]本网转载网络媒体稿件是为了传播更多的信息,此类稿件不代表本网观点,本网不承担此类稿件侵权行为的连带责任。故此,如果您发现本网站的内容侵犯了您的版权,请您的相关内容发至此邮箱【27535611@qq.com】,我们在确认后,会立即删除,保证您的版权。