оператор yield return не может появляться в ограничении блока try / catch

c#

2665 просмотра

4 ответа

Эти два метода практически одинаковы, но первый не может быть скомпилирован. Я не могу понять причину этого ограничения

    /// <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;
        }
    }
Автор: bevacqua Источник Размещён: 12.11.2019 09:49

Ответы (4)


7 плюса

Решение

Вы можете получить ответ на этот вопрос в серии Эрика Липперта о блоках итераторов. В частности, ознакомьтесь с публикацией под названием « Блоки итераторов», часть пятая: «Push против Pull» . Серия из семи частей начинается с блоков итераторов, часть первая .

Автор: jason Размещён: 03.11.2011 02:25

6 плюса

Эрик Липперт подробно объясняет это в своей серии статей о блоках итераторов . Начните снизу и продолжайте свой путь вверх, и не пропускайте ничего, пока не достигнете нужного момента.

Я не буду пытаться объяснить это дальше - я процитирую часть поста 5 , который на самом деле посвящен tryблокам, которые имеют catchблоки (пост 4 рассказывает о catchсамих блоках, но это другой вопрос).

Так что, если блок try имеет подвох?

У оригинальных дизайнеров C # 2.0 - и помните, это задолго до моего пребывания в команде - была большая дискуссия по этому поводу. Дискуссия, которая повторялась в миниатюре, когда я отправил им электронное письмо с просьбой обосновать это решение. Есть три основных положения:

  1. Ни в коем случае не допускайте возврат доходности в блоках try. (Или блоки, которые являются сахарами для блоков try, например, с использованием блоков.) Используйте другой механизм, отличный от «finally», чтобы выразить идею «это код, который вы запускаете, когда вызывающая сторона выключает перечисление».

  2. Разрешить возврат урожая во всех блоках try.

  3. Разрешить возвращение yield в блоках try, в которых есть блоки finally, но не в том случае, если в них есть блоки catch.

[Надрез]

Недостатком (3) является то, что правило кажется произвольным и странным - пока вы не прочитаете пять ненужных записей в блоге, которые объясняют, что на самом деле думала команда разработчиков.

Очевидно, они выбрали (3), и теперь вы знаете, почему.

Автор: Jon Skeet Размещён: 03.11.2011 02:28

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 не хочет делать эту работу, поэтому вы должны сделать это самостоятельно (ленивый компилятор)

Автор: Toto Размещён: 03.11.2011 02:32

-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; } } }
Автор: Basil Размещён: 16.02.2012 05:58
Вопросы из категории :
32x32