Domanda

Ho un oggetto LINQ con un metodo aggiuntivo aggiunto ad esso. La classe non ha proprietà o metodi usa e getta, ma FxCop sta generando l'errore "I tipi che possiedono i campi usa e getta dovrebbero essere usa e getta" e facendo riferimento a quella classe.

Ho ridotto il codice fino a questo punto e continuo a ricevere l'errore:

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

Tuttavia, se rimuovo OGNI delle clausole from, FxCop smette di dare l'errore:

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 non è usa e getta.

È un falso positivo? O il codice LINQ sta in qualche modo generando un campo usa e getta sulla classe? Se non è un falso positivo, FxCop mi consiglia di implementare l'interfaccia IDisposable, ma cosa farei nel metodo Dispose?

EDIT: L'errore FxCop completo è:

  

" Implementare IDisposable su 'WikiPage' perché   crea membri dei seguenti tipi IDisposable:   'WikiTomeDataContext'. Se "WikiPage" ha precedentemente   spedito, aggiungendo nuovi membri che implementano IDisposable   a questo tipo viene considerata una modifica sostanziale a quella esistente   . I consumatori "

Modifica 2: Questo è il codice disassemblato che genera l'errore:

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

Modifica 3: Sembra che ci sia una classe di chiusura contenente un riferimento a DataContext. Ecco il suo codice smontato:

<*>
È stato utile?

Soluzione

La mia ipotesi è che le due clausole From generino una chiamata a SelectMany con una chiusura nel contesto dei dati. L'istanza della chiusura ha un campo nel datacontext che causa l'avviso FxCop. Non c'è niente di cui preoccuparsi.

Esiste solo un'istanza del tuo datacontext, che pulisci tramite il blocco using. Poiché la chiusura non ha un finalizzatore, non ci sono prestazioni o implicazioni di sicurezza qui nell'avviso FxCop.

Altri suggerimenti

Ho notato che questa è una classe parziale. Hai controllato l'altro file di implementazione per la classe e vedi se ha un membro IDisposable che non viene eliminato?

Non credo che la chiusura generata sia in colpa qui. Le chiusure vengono generate con determinati attributi che dovrebbero far sì che FxCop ignori avvisi come questo.

MODIFICA

Ulteriori indagini da parte dell'OP hanno dimostrato che si tratta di un problema relativo alla chiusura di un campo IDisposable.

Sfortunatamente non puoi fare molto al riguardo. Non è possibile rendere IDisposable l'attrezzo di chiusura. Evento, se possibile, non è possibile chiamare IDisposable sull'istanza di chiusura.

Il modo migliore per affrontare questo problema è riscrivere il codice in modo tale che un valore usa e getta non venga catturato nella chiusura. I campi usa e getta devono sempre essere eliminati quando sono finiti e catturarlo in una chiusura ti impedisce di farlo.

Se stai restituendo una query LINQ dal tuo metodo, i consumatori eseguiranno l'iterazione sui risultati utilizzando foreach.

Quando un consumatore termina un ciclo foreach, chiama internamente dispose sull'origine IEnumerable (in questo caso, la tua query LINQ). Questo eliminerà WikiTomeDataContext.

Tuttavia, se un consumatore ha effettuato una chiamata al metodo restituendo una query LINQ ma non ha mai ripetuto i risultati, sembrerebbe che l'enumerabile non verrà mai eliminato (vale a dire fino a quando il garbage collector non ripulisce l'oggetto). Ciò porterebbe a WikiTomeDataContext non essere smaltito fino alla raccolta dei rifiuti.

Un modo per aggirare questo problema è chiamare .ToArray sul risultato della query LINQ, chiamare dispose sul proprio contesto, quindi restituire l'array.

Il codice che fornisce l'errore utilizza WikiDataContext.

I tuoi due esempi che non danno un errore usano WikiTomeDataContext.

Forse c'è una differenza tra questi due che sta causando l'errore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top