2009-08-02 3 views
2

Ich habe ein LINQ-Objekt mit einer zusätzlichen Methode hinzugefügt. Die Klasse hat keine wegwerfbaren Eigenschaften oder Methoden, aber FxCop löst den Fehler "Typen, die Einwegfelder besitzen, sollte wegwerfbar sein" und auf diese Klasse verweisen.Warum löst FxCop den Fehler "Typen, die Einwegfelder besitzen, für eine Klasse ohne verfügbare Felder aus?"

ich den Code so weit reduziert haben und erhalten immer noch den Fehler:

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

Wenn ich jedoch eine der beiden von Klauseln entfernen, stoppt FxCop den Fehler geben:

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

      return null; 
     } 
    } 
} 

Or

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 ist nicht Einweg.

Ist das ein falsch positives Ergebnis? Oder erzeugt der LINQ-Code irgendwie ein Einwegfeld in der Klasse? Wenn es kein falscher positiver Wert ist, empfiehlt FxCop, die IDisposable-Schnittstelle zu implementieren, aber was würde ich in der Dispose-Methode tun?

EDIT: Der vollständige FxCop Fehler ist:

"Implement IDisposable on 'WikiPage' because it creates members of the following IDisposable types: 'WikiTomeDataContext'. If 'WikiPage' has previously shipped, adding new members that implement IDisposable to this type is considered a breaking change to existing consumers."

Edit 2: Dies ist der demontierten Code, der den Fehler auslöst:

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

Bearbeiten 3: Es scheint zu sein, eine Closure-Klasse, die einen Verweis auf den DataContext enthält. Hier ist sein zerlegter Code:

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

    // Methods 
    public <>c__DisplayClass1(); 
} 

Antwort

3

Meine Vermutung ist, dass die beiden From Klauseln einen Aufruf an mit einer Schließung auf Ihrem Datenkontext generieren. Die Instanz der Schließung hat ein Feld zum Datenkontext, das die FxCop-Warnung verursacht. Das ist kein Grund zur Sorge.

Es gibt nur eine Instanz Ihres Datenkontexts, den Sie über den using-Block bereinigen. Da die Schließung keinen Finalizer hat, gibt es hier in der FxCop-Warnung keine Leistung oder Sicherheit.

+0

Das klingt plausibel. Wenn dies der Fall ist, muss ich etwas unternehmen, um sicherzustellen, dass der DataContext entsorgt wird? – AaronSieb

+0

Es gibt nichts, worüber man sich Sorgen machen müsste. Es gibt nur eine Instanz Ihres Datenkontextes, den Sie über den using-Block bereinigen. b/c Der Abschluss hat keinen Finalizer, hier gibt es keine Perforationen. –

+0

Danke! Ich werde diesen Fehler dann in die Ausschlussliste verschieben. – AaronSieb

0

Ihr Code, der den Fehler gibt, verwendet WikiDataContext.

Ihre beiden Beispiele, die keinen Fehler enthalten, verwenden den WikiTomeDataContext.

Vielleicht gibt es einen Unterschied zwischen diesen beiden, der den Fehler verursacht.

+0

Guter Fang, aber das scheint es nicht zu sein. Ich habe meine Frage bearbeitet, um konsistente Beispiele zu verwenden. – AaronSieb

2

Ich bemerkte, dass dies eine partielle Klasse ist. Haben Sie die andere Implementierungsdatei für die Klasse überprüft und überprüft, ob sie ein IDisposable-Member enthält, das nicht entfernt wird?

Ich glaube nicht, dass die generierte Schließung hier fehlerhaft ist. Verschlüsse werden mit bestimmten Attributen erzeugt, die dazu führen sollten, dass FxCop Warnungen wie diese ignoriert.

EDIT

Weitere Untersuchungen durch die OP ergab dies ein Problem mit einem IDisposable Bereich zu sein, der in ein Schließ angehoben.

Leider kann man da nicht viel machen. Es gibt keine Möglichkeit, die IDDisposable für die Schließung zu implementieren. Event, wenn es möglich ist, gibt es keine Möglichkeit IDisposable für die Closing-Instanz aufzurufen.

Die beste Möglichkeit, dieses Problem anzugehen, besteht darin, den Code so umzuschreiben, dass ein wegwerfbarer Wert nicht im Abschluss erfasst wird. Einweg-Felder sollten immer entsorgt werden, wenn sie fertig sind und die Aufnahme in einem Verschluss verhindert dies.

+0

Wenn ich die obige Methode entferne, erzeugt FxCop den Fehler nicht. Ich habe auch den disassemblierten Code für die Klasse durchgesehen und scheint keine IDisposable-Eigenschaften von Variablen auf Klassenebene zu haben. – AaronSieb

+0

@AaronSieb, interessant. Haben Sie die generierte Schließklasse untersucht, um festzustellen, ob eines ihrer Mitglieder IDisposable implementiert? – JaredPar

+0

@JaredPar Wie würde ich das tun? Ich bin ein wenig verschwommen auf das Konzept der Schließungen ... Der disassemblierte Code (über .NET Reflektor) wurde am Ende meiner Frage angehängt, wenn das hilft. – AaronSieb

1

Wenn Sie eine LINQ-Abfrage von Ihrer Methode zurückgeben, werden die Benutzer die Ergebnisse mithilfe von foreach iterieren.

Wenn ein Benutzer eine foreach-Schleife beendet, ruft er intern die IEnumerable-Quelle auf (in diesem Fall Ihre LINQ-Abfrage). Dadurch wird der WikiTomeDataContext entfernt. Wenn ein Benutzer einen Aufruf an die Methode abgab, die eine LINQ-Abfrage zurücksendet, aber nie über die Ergebnisse iterierte, würde es so aussehen, als würde der Enumerable niemals entfernt werden (bis der Garbage Collector das Objekt bereinigt hat). Dies würde dazu führen, dass Ihr WikiTomeDataContext erst bei der Garbage Collection entsorgt wird.

Eine Möglichkeit, um dieses Problem zu umgehen, ist durch Aufruf von .ToArray auf das Ergebnis Ihrer LINQ-Abfrage, rufen Sie den Kontext ab und geben Sie das Array zurück.

+0

Das hilft. Aus dem Beispielcode geht dies nicht hervor, aber LINQ IEnumerable wird nicht zurückgegeben. Wenn der DataContext bei der Ausführung des GC ordnungsgemäß entsorgt wird, mache ich mir etwas weniger Sorgen. – AaronSieb

Verwandte Themen