C# 本地函数与yield语句

6cb6ecf23f7c937f34492bd5889f587f.png

Where 方法的一个简单实现,下面将其添加 Where1 方法的实现中,检查 source和 predicate 参数是否为null:

public static IEnumerable<T> Wherel<T>(this IEnumerable<T> source, 
  Func<T,bool> predicate)
{
  if (source == null) throw new ArgumentNullException(nameof(source));
  if (predicate == null) throw new ArgumentNullException(nameof(predicate));


  foreach (T item in source)
  {
    if (predicate(item)) 
    {
      yield return item;
    }
  }
}

编写代码测试 ArgumentNullException,定义预处理语句 #line,以从源代码行 1000开始。在第 1004 行中没有发生异常,其中 null 传递给 Where1 方法;相反,在第1006 行中包含的 foreach 语句发生了异常。延迟发现这个的原因是,在方法 Where1的实现中,延迟执行了 yield 语句。 

private static void YieldSampleSimple()
{
#line 1000  
  Console.WriteLine(nameof(YieldSampleSimple)); 
  try
  {
    string[] names = { "James", "Niki", "John", "Gerhard", "Jack" }; 
    var q = names.Wherel(null);
    
    foreach (var n in q)  // callstack position for exception
    {
      Console.WriteLine(n);
    }
  }
  catch (ArgumentNullException ex)
  {
    Console.WriteLine(ex);
  }
  Console.WriteLine();
}

为了解决这个问题,并向调用者更早地提供错误信息,Where1 方法通过 Where2 方法在两个部分实现。这里,Where2 方法只检查不正确的参数,不包括 yield 语句。使用 yield return 的实现是在一个单独的私有方法 WhereImpl 中完成的。在检查输入参数之后,从 Where2 方法中调用此方法。

public static IEnumerable<T> Where2<T>(this IEnumerable<T> source, 
  Func<T, bool> predicate)
{
  if (source == null) throw new ArgumentNullException(nameof(source)); 
  if (predicate == null) throw new ArgumentNullException(nameof(predicate));
  
  return Where2Impl(source, predicate);
}
  
private static IEnumerable<T> Where2Impl<T>(IEnumerable<T> source,
  Func<T, bool> predicate)
{
  foreach (T item in source)
  {
    if (peedicate(item)) 
    {
       yield return item;
       }
    }
}

现在调用该方法,堆栈跟踪显示在第 1004 行中发生的错误,其中调用了 Where2方法:

private static void YieldSampleWithPrivateMethod() 
{
#line 1000
  Console.WriteLine(nameof(YieldSampleWithPrivateMethod));
  try
  {
  string[] names = { "James", "Niki", "John", "Gerhard", "Jack" };
  var q = names.Where2(mull);  // callstack position for erception 
  
  foreach (var n in q) 
  {
    Console.WriteLine(n);
  }
}
catch (ArgumentNullException ex)
{
    Console.WriteLine(ex); 
  }
  Console.WriteLine();
}

这个问题是用 Where2 方法解决的。但是,现在有了一个仅需要在一个地方使用的私有方法。Where2 方法的主体包括参数检查和 Where2Impl 方法的调用。对于私有方法来说,这是一个很好的场景。Where3 方法的实现包括对输入参数的检查(与以前一样),以及一个私有函数,而不是以前的私有方法 Where2Impl。本地函数可以有更简单的签名,因为它可以从外部作用域访问变量的源和谓词:

public static IEnumerable<T> Where3<T>(this IEnumerable<T> source, 
  Func<T,bool> predicate)
{
  if (source == null) throw new ArgumentNullException (nameof (source));
  if (predicate == null) throw new ArgumentNullException (nameof (predicate)); 
  
  return Iterator();
  
  IEnumerable<T> Iterator() 
  {
    foreach (T item in source) 
    {
      if (predicate(item)) 
      {
         yield return item;
      }
    }
  }
}

调用 Where3 方法,其结果与调用 Where2 方法的结果相同。堆栈跟踪显示了调用 Where3 方法的问题。

技术群:添加小编微信并备注进群

小编微信:mm1552923   

公众号:dotNet编程大全      

往期推荐

·  C# 数据流

·  C# 类型系统

·  C# 面向对象的编程

·  C# 执行 SQL 语句

·  C# 连接数据库

·  C# 迭代器

f6f9720cfbc6c46fd186d3092c6fcdce.png

Love life,love yourself

关注小编不迷路呦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值