【问题标题】:.NET iterator to wrap throwing API.NET 迭代器来包装投掷 API
【发布时间】:2011-05-01 21:17:26
【问题描述】:

我有一个带有 API 的类,它允许我请求对象,直到它抛出 IndexOutOfBoundsException

我想将它包装到一个迭代器中,以便能够编写更清晰的代码。但是,我需要捕获异常以停止迭代:

static IEnumerable<object> Iterator( ExAPI api ) {
    try {
       for( int i = 0; true; ++i ) {
          yield return api[i]; // will throw eventually
       }
    } 
    catch( IndexOutOfBoundsException ) {
       // expected: end of iteration.
    }
}

但是……

与表达式一起使用时,yield return 语句不能出现在 catch 块或 try 块中 一个或多个 catch 子句。更多 信息,请参阅异常处理 语句(C# 参考)。语句(C# 参考)。 (来自msdn

我该如何包装这个 api?

【问题讨论】:

    标签: c# .net exception yield-return


    【解决方案1】:

    您只需将yield return 语句移到try 块之外,如下所示:

    static IEnumerable<object> Iterator( ExAPI api ) {
       for( int i = 0; true; ++i ) {
            object current;
            try {
                current = api[i];
            } catch(IndexOutOfBoundsException) { yield break; }
    
            yield return current;
        } 
    }
    

    【讨论】:

    • 虽然你不需要“if (current != null) yield return current”吗?
    • 哦,等等,我很笨,我错过了产量突破。
    • yield break 声明文档留在 msdn 上...感谢您的指出!
    【解决方案2】:

    只需重新排序代码:

    static IEnumerable<object> Iterator( ExAPI api ) {
        bool exceptionThrown = false;
        object obj = null;
        for( int i = 0; true; ++i ) {
            try {
                obj = api[i];
            }
            catch( IndexOutOfBoundsException ) {
                exceptionThrown = true;
                yield break;
            }
    
            if (!exceptionThrown) {
                yield return obj;
            }
        }
    }
    

    【讨论】:

    • 不,我猜我写得太快了......无论如何,你下面的答案更干净更好:-)
    • 现在你有了一个无用的变量。
    • 是的 - 但如果我改变了它,我的答案将是你答案的直接副本,即使它是正确的,那也会有点蹩脚 - 你编写了正确的代码,你应该得到信用!
    【解决方案3】:

    您可以将获取对象的简单操作包装到单独的函数中。您可以在其中捕获异常:

    bool TryGetObject( ExAPI api, int idx, out object obj )
    {
        try
        {
            obj = api[idx];
            return true;
        }
        catch( IndexOutOfBoundsException )
        {
            return false;
        }        
    }
    

    然后,调用该函数并在必要时终止:

    static IEnumerable<object> Iterator( ExAPI api )
    {
       bool abort = false;
    
        for( int i = 0; !abort; ++i )
        {
            object obj;
            if( TryGetObject( api, i, out obj ) )
            {
                yield return obj;
            }
            else
            {
                abort = true;
            }
        }
    }
    

    【讨论】:

    • 我不太喜欢这种方法。如果 api 只打算在这个方法中被访问,那么一个单独的方法来获取对象是有点多余的。
    【解决方案4】:

    如果你根本无法检查对象的边界,你可以这样做

    static IEnumerable<object> Iterator( ExAPI api )
    {
     List<object> output = new List<object>();
        try
     {
      for( int i = 0; true; ++i )
       output.Add(api[i]);
        } 
        catch( IndexOutOfBoundsException )
     {
      // expected: end of iteration.
        }
     return output;
    }
    

    虽然现在我在看这里,但我相信上面的答案更好。一个 SLaks 发布的。

    【讨论】:

    • 确实:我的目的不是填充容器,而是提供一个迭代器。
    【解决方案5】:
        static IEnumerable<object> Iterator(ExAPI api)
        {
            int i = 0;
            while (true)
            {
                Object a;
                try
                {
                    a = api[i++];
                }
                catch (IndexOutOfBoundsException)
                {
                    yield break;
                }
                yield return a;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      • 2014-10-24
      • 2016-06-23
      • 2015-12-12
      相关资源
      最近更新 更多