Почему FxCop выдает ошибку «Типы, владеющие одноразовыми полями, должны быть одноразовыми» в классе без одноразовых полей?

StackOverflow https://stackoverflow.com/questions/1219086

  •  10-07-2019
  •  | 
  •  

Вопрос

У меня есть объект LINQ, к которому добавлен дополнительный метод.У класса нет одноразовых свойств или методов, но FxCop выдает ошибку «Типы, которым принадлежат одноразовые поля, должны быть одноразовыми» и ссылается на этот класс.

Я сократил код настолько сильно, но все равно получаю сообщение об ошибке:

partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from wiki in context.Wikis
                from pageTag in context.VirtualWikiPageTags
                select new {};

            return null;
        }
    }
}

Однако, если я удалю ЛЮБОЕ из предложений from, FxCop перестанет выдавать ошибку:

partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from pageTag in context.VirtualWikiPageTags
                select new {};

            return null;
        }
    }
}

Или

partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from wiki in context.Wikis
                select new {};

            return null;
        }
    }
}

PagePermissionSet не является одноразовым.

Это ложное срабатывание?Или код LINQ каким-то образом генерирует одноразовое поле в классе?Если это не ложное срабатывание, FxCop рекомендует реализовать интерфейс IDisposable, но что мне делать в методе Dispose?

РЕДАКТИРОВАТЬ:Полная ошибка FxCop:

"Реализуйте Idisposable на« Wikipage », потому что он создает членов следующих типов Idisposable:«Контекст WikiTomeDataContext».Если «Wikipage» ранее отправился, добавление новых участников, которые реализуют Idisposable к этому типу, считается нарушением изменений для существующих потребителей ».

Редактировать 2:Это дизассемблированный код, который вызывает ошибку:

public PagePermissionSet GetUserPermissions(Guid? userId)
{
    using (WikiTomeDataContext context = new WikiTomeDataContext())
    {
        ParameterExpression CS$0$0001;
        ParameterExpression CS$0$0003;
        var permissions = context.Wikis.SelectMany(Expression.Lambda<Func<Wiki, IEnumerable<VirtualWikiPageTag>>>(Expression.Property(Expression.Constant(context), (MethodInfo) methodof(WikiTomeDataContext.get_VirtualWikiPageTags)), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki") }), Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType8..ctor), new Expression[0], new MethodInfo[0]), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki"), CS$0$0003 = Expression.Parameter(typeof(VirtualWikiPageTag), "pageTag") }));
        return null;
    }
}

Редактировать 3:Кажется, существует класс закрытия, содержащий ссылку на DataContext.Вот его дизассемблированный код:

[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
    // Fields
    public WikiTomeDataContext context;

    // Methods
    public <>c__DisplayClass1();
}
Это было полезно?

Решение

Я предполагаю, что эти двое From предложения генерируют вызов SelectMany с закрытием контекста ваших данных.Экземпляр замыкания имеет поле в контексте данных, которое вызывает предупреждение FxCop.Не о чем беспокоиться.

Существует только один экземпляр вашего контекста данных, который вы очищаете с помощью блока using.Поскольку у замыкания нет финализатора, предупреждение FxCop не влияет на производительность или безопасность.

Другие советы

Я заметил, что это частичный класс.Проверили ли вы другой файл реализации класса и посмотрите, есть ли в нем элемент IDisposable, который не удаляется?

Я не думаю, что сгенерированное замыкание здесь виновато.Замыкания генерируются с определенными атрибутами, которые должны заставить FxCop игнорировать подобные предупреждения.

РЕДАКТИРОВАТЬ

Дальнейшее расследование, проведенное ОП, показало, что это проблема, связанная с закрытием поля IDisposable.

К сожалению, вы мало что можете с этим поделать.Невозможно реализовать замыкание IDisposable.Событие, если бы вы могли, невозможно вызвать IDisposable для экземпляра закрытия.

Лучший способ решить эту проблему — переписать код таким образом, чтобы одноразовое значение не попадало в замыкание.Одноразовые поля всегда следует удалять, когда они завершены, и их захват в замыкание не позволяет вам сделать это.

Если вы возвращаете запрос LINQ из своего метода, потребители будут перебирать результаты, используя foreach.

Когда потребитель завершает цикл foreach, он внутренне вызывает метод Dispose для источника IEnumerable (в данном случае — вашего запроса LINQ).Это приведет к удалению WikiTomeDataContext.

Однако если потребитель вызвал метод, возвращающий запрос LINQ, но никогда не перебирал результаты, может показаться, что перечисляемый объект никогда не будет удален (то есть до тех пор, пока сборщик мусора не очистит объект).Это приведет к тому, что ваш WikiTomeDataContext не будет удален до момента сбора мусора.

Один из способов обойти эту проблему — вызвать .ToArray по результату вашего запроса LINQ, вызвать Dispose в вашем контексте, а затем вернуть массив.

Ваш код, который выдает ошибку, использует WikiDataContext.

В двух ваших примерах, которые не выдают ошибку, используется WikiTomeDataContext.

Возможно, между этими двумя есть какая-то разница, которая вызывает ошибку.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top