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

У меня есть объект 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;
        }
    }
}

Однако, если я удалю EITHER из предложений 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?

EDIT: Полная ошибка 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();
}

Ответы [ 4 ]

3 голосов
/ 02 августа 2009

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

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

2 голосов
/ 02 августа 2009

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

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

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

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

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

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

1 голос
/ 02 августа 2009

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

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

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

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

0 голосов
/ 02 августа 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...