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エラーは次のとおりです。

  

"「WikiPage」にIDを実装可能   次のIDisposable型のメンバーを作成します。   「WikiTomeDataContext」。 「WikiPage」が以前に持っている場合   出荷、IDisposableを実装する新しいメンバーを追加   このタイプへの変更は、既存の   消費者。"

編集2: これは、エラーを発生させる逆アセンブルされたコードです。

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

編集3: DataContextへの参照を含むクロージャークラスがあるようです。逆アセンブルされたコードは次のとおりです。

<*>
役に立ちましたか?

解決

2つの From 句は、データコンテキストでクロージャーを使用して SelectMany の呼び出しを生成すると思います。クロージャーのインスタンスには、FxCop警告の原因となるデータコンテキストへのフィールドがあります。これは心配することではありません。

datacontextのインスタンスは1つのみで、usingブロックを使用してクリーンアップします。クロージャにはファイナライザがないため、FxCop警告にはパフォーマンスや安全性への影響はありません。

他のヒント

これは部分クラスであることに気付きました。クラスの別の実装ファイルを確認し、破棄されていないIDisposableメンバーが含まれているかどうかを確認しましたか?

ここでは、生成されたクロージャーに問題があるとは思わない。 FxCopにこのような警告を無視させる特定の属性を使用してクロージャーが生成されます。

編集

OPによるさらなる調査により、これはIDisposableフィールドが閉鎖されている問題であることが示されました。

残念ながら、これに関してできることはあまりありません。クロージャーにIDisposableを実装させる方法はありません。クロージャーインスタンスでIDisposableを呼び出す方法がない場合のイベント。

この問題に取り組む最良の方法は、使い捨ての値がクロージャーに取り込まれないようにコードを書き直すことです。使い捨てフィールドは、終了時に必ず廃棄する必要があり、クロージャでキャプチャすると、これを実行できなくなります。

メソッドからLINQクエリを返す場合、消費者はforeachを使用して結果を反復処理します。

コンシューマーがforeachループを完了すると、IEnumerableソース(この場合はLINQクエリ)で内部的にdisposeを呼び出します。これにより、WikiTomeDataContextが破棄されます。

ただし、コンシューマーがLINQクエリを返すメソッドを呼び出したが、結果を繰り返し処理しなかった場合、enumerableは破棄されないように見えます(つまり、ガベージコレクターがオブジェクトをクリーンアップするまで)。これにより、WikiTomeDataContextがガベージコレクションまで破棄されなくなります。

この問題を回避できる1つの方法は、LINQクエリの結果で.ToArrayを呼び出し、コンテキストでdisposeを呼び出し、配列を返すことです。

エラーを与えるコードはWikiDataContextを使用します。

エラーを与えない2つの例では、WikiTomeDataContextを使用します。

たぶん、エラーを引き起こしているこれら2つの間にいくつかの違いがあります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top