'yield return'语句不能出现在try / catch块约束中

时间:2011-11-03 14:23:04

标签: c#

这两种方法几乎相同,但第一种方法无法编译。我无法弄清楚这种约束存在的原因

    /// <summary>
    /// Dynamically loads all document extractors from implementation assemblies into an enumeration
    /// </summary>
    private static IEnumerable<IDocumentExtractor> EnumerateInstances()
    {
        IEnumerable<Type> types = EnumerateTypes();

        foreach(Type type in types)
        {
            try
            {
                IDocumentExtractor extractor = Activator.CreateInstance(type) as IDocumentExtractor;
                yield return extractor;
            }
            catch
            {
                _log.WarnFormat("Type {0} couldn't be instanced.", type.Name);
            }
        }
    }

实际编译的版本没有问题:

    /// <summary>
    /// Dynamically loads all document extractors from implementation assemblies into an enumeration
    /// </summary>
    private static IEnumerable<IDocumentExtractor> EnumerateInstances()
    {
        IEnumerable<Type> types = EnumerateTypes();

        foreach (Type type in types)
        {
            IDocumentExtractor extractor = null;
            try
            {
                extractor = Activator.CreateInstance(type) as IDocumentExtractor;
            }
            catch
            {
                _log.WarnFormat("Type {0} couldn't be instanced.", type.Name);
            }

            if (extractor != null)
                yield return extractor;
        }
    }

4 个答案:

答案 0 :(得分:7)

你可以在Eric Lippert的Iterator Blocks系列中找到这个问题的答案。具体来看,标题为Iterator Blocks, Part Five: Push vs Pull的帖子。这个由七部分组成的系列以Iterator Blocks, Part One开头。

答案 1 :(得分:6)

Eric Lippert在他的blog series about iterator blocks中详细解释了这一点。从底部开始向前走,并且在你到达正确位置之前不要跳过任何东西。

我不打算在此之外解释它 - 但我会引用post 5的一部分,这实际上是谈论trycatch的部分块(帖子4讨论catch阻止自己,但这是另一回事。)

  

那么如果try块有一个catch呢?

     

C#2.0的原始设计师 - 请记住,这是我在团队工作之前很久 - 对此进行了大量辩论。当我向他们发送一封电子邮件询问这一决定的理由时,这个辩论以微缩的形式重复出现。有三个基本立场:

     
      
  1. 根本不允许在try块中返回yield。 (或者像try块一样的块,比如使用块。)使用除“finally”之外的其他一些机制来表达“这是调用者关闭枚举时运行的代码。”

  2.   
  3. 允许所有try块返回产量。

  4.   
  5. 允许在最后有块的try块中返回yield,但是如果它们有catch块则不返回。

  6.         

    [剪断]

         

    (3)的缺点是规则似乎是任意而且奇怪 - 直到你阅读了五个不必要的冗长的博客条目来解释设计团队在想什么。

         

    显然,他们选择了(3),现在你知道为什么了。

答案 2 :(得分:0)

但你可以写:

private static IEnumerable<IDocumentExtractor> EnumerateInstances()
{
    IEnumerable<Type> types = EnumerateTypes();

    foreach(Type type in types)
    {
        var oResult = Test(type);
        if (oResult != null)
        {
            yield return oResult;
        }
    }
}

private static IDocumentExtractor Test(Type type)
{
    try
    {
        IDocumentExtractor extractor = Activator.CreateInstance(type) as IDocumentExtractor;
         return extractor;
    }
    catch
    {
        return null;
        //_log.WarnFormat("Type {0} couldn't be instanced.", type.Name);
    }
}

只是Visual Studio不想做这个工作,所以你必须自己做(懒惰的编译器)

答案 3 :(得分:-1)

   public static IEnumerable IListFind(IEnumerable list, ConditionHandler handler, EventHandler errorHandler = null, DateTime? started = null)
    {
        try
        {
            if (started == null) { started = DateTime.Now; };
            return IListFindInternal(list, handler);
        }
        catch
        {
            if (DateTime.Now.Subtract(started.Value).TotalSeconds < 30)
            {
                if (errorHandler != null) { errorHandler(list, EventArgs.Empty); };
                return IListFind(list, handler, errorHandler, started);
            }
            else
            {
                return null;
            }
        }
    }

    public static IEnumerable IListFindInternal(IEnumerable list, ConditionHandler handler) { foreach (object item in list) { if (handler(item)) { yield return item; } } }