¿Por qué FxCop genera el error "Los tipos que poseen campos desechables deberían ser desechables" en una clase sin campos desechables?

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

  •  10-07-2019
  •  | 
  •  

Pregunta

Tengo un objeto LINQ con un método adicional agregado. La clase no tiene propiedades o métodos desechables, pero FxCop está generando el error "Tipos que poseen campos desechables deben ser desechables". y haciendo referencia a esa clase.

He reducido el código hasta ahora y sigo recibiendo el error:

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;
        }
    }
}

Sin embargo, si elimino CUALQUIERA de las cláusulas from, FxCop deja de dar el error:

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

            return null;
        }
    }
}

O

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 no es desechable.

¿Es esto un falso positivo? ¿O el código LINQ de alguna manera genera un campo desechable en la clase? Si no es un falso positivo, FxCop recomienda que implemente la interfaz IDisposable, pero ¿qué haría en el método Dispose?

EDITAR: El error completo de FxCop es:

  

" Implementar IDisposable en 'WikiPage' porque   crea miembros de los siguientes tipos IDisposable:   'WikiTomeDataContext'. Si 'WikiPage' tiene previamente   enviado, agregando nuevos miembros que implementan IDisposable   a este tipo se considera un cambio radical a los existentes   consumidores. "

Editar 2: Este es el código desmontado que genera el error:

public PagePermissionSet GetUserPermissions(Guid? userId)
{
    using (WikiTomeDataContext context = new WikiTomeDataContext())
    {
        ParameterExpression CS
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
    // Fields
    public WikiTomeDataContext context;

    // Methods
    public <>c__DisplayClass1();
}
$0001; ParameterExpression CS<*>$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<*>$0001 = Expression.Parameter(typeof(Wiki), "wiki") }), Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType8..ctor), new Expression[0], new MethodInfo[0]), new ParameterExpression[] { CS<*>$0001 = Expression.Parameter(typeof(Wiki), "wiki"), CS<*>$0003 = Expression.Parameter(typeof(VirtualWikiPageTag), "pageTag") })); return null; } }

Editar 3: Parece haber una clase de cierre que contiene una referencia al DataContext. Aquí está su código desmontado:

<*>
¿Fue útil?

Solución

Supongo que las dos cláusulas From generan una llamada a SelectMany con un cierre en su contexto de datos. La instancia del cierre tiene un campo para el contexto de datos que causa la advertencia de FxCop. No hay de qué preocuparse.

Solo hay una instancia de su contexto de datos, que limpia mediante el bloque de uso. Debido a que el cierre no tiene un finalizador, no hay implicación de rendimiento o seguridad aquí en la advertencia de FxCop.

Otros consejos

Noté que esta es una clase parcial. ¿Ha verificado el otro archivo de implementación para la clase y ha visto si tiene un miembro IDisposable que no se está eliminando?

No creo que el cierre generado sea el culpable aquí. Los cierres se generan con ciertos atributos que deberían hacer que FxCop ignore advertencias como esta.

EDITAR

Una investigación adicional por parte del OP demostró que se trata de un problema con un campo IDisposable que se levanta a un cierre.

Desafortunadamente no hay mucho que puedas hacer al respecto. No hay forma de hacer que el cierre implemente IDisposable. Si pudiera, no hay forma de llamar a IDisposable en la instancia de cierre.

La mejor manera de abordar este problema es reescribir su código de tal manera que no se capture un valor desechable en el cierre. Los campos desechables siempre deben desecharse cuando estén terminados y capturarlos en un cierre le impide hacerlo.

Si devuelve una consulta LINQ desde su método, los consumidores iterarán sobre los resultados usando foreach.

Cuando un consumidor finaliza un bucle foreach, internamente llama a dispose en la fuente IEnumerable (en este caso, su consulta LINQ). Esto eliminará el WikiTomeDataContext.

Sin embargo, si un consumidor realiza una llamada al método que devuelve una consulta LINQ pero nunca repite los resultados, parecería que nunca se eliminaría el enumerable (es decir, hasta que el recolector de basura limpiara el objeto). Esto llevaría a que su WikiTomeDataContext no se elimine hasta la recolección de basura.

Una forma en que podría solucionar este problema es llamando a .ToArray sobre el resultado de su consulta LINQ, llame a dispose en su contexto y luego devuelva la matriz.

Su código que da el error usa WikiDataContext.

Sus dos ejemplos que no dan un error usan WikiTomeDataContext.

Quizás haya alguna diferencia entre estos dos que esté causando el error.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top