Linq 为什么FxCop会提出错误;拥有一次性字段的类型应该是一次性的;在没有一次性字段的类上?

Linq 为什么FxCop会提出错误;拥有一次性字段的类型应该是一次性的;在没有一次性字段的类上?,linq,idisposable,fxcop,Linq,Idisposable,Fxcop,我有一个LINQ对象,其中添加了一个附加方法。该类没有可丢弃的属性或方法,但FxCop正在引发错误“拥有可丢弃字段的类型应该是可丢弃的”,并引用该类 到目前为止,我已经减少了代码,但仍然收到错误: partial class WikiPage { public PagePermissionSet GetUserPermissions(Guid? userId) { using (WikiTomeDataContext context = new WikiTomeDataC

我有一个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;
        }
    }
}
partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from pageTag in context.VirtualWikiPageTags
                select new {};

            return null;
        }
    }
}
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;
    }
}
但是,如果我删除其中一个from子句,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;
        }
    }
}
partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from pageTag in context.VirtualWikiPageTags
                select new {};

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

PagePermissionSet不是一次性的

这是假阳性吗?或者LINQ代码以某种方式在类上生成了一个一次性字段?如果不是误报,FxCop建议我实现IDisposable接口,但是在Dispose方法中我会怎么做

编辑: 完整的FxCop错误为:

“在“WikiPage”上实现IDisposable,因为它 创建以下IDisposable类型的成员: “WikiTomeDataContext”。如果“WikiPage”以前 已发布,添加实现IDisposable的新成员 对该类型的更改被视为对现有 消费者。”

编辑2: 这是引发错误的反汇编代码:

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;
        }
    }
}
partial class WikiPage
{
    public PagePermissionSet GetUserPermissions(Guid? userId) {
        using (WikiTomeDataContext context = new WikiTomeDataContext()) {
            var permissions =
                from pageTag in context.VirtualWikiPageTags
                select new {};

            return null;
        }
    }
}
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;
    }
}
publicpagepermissionset GetUserPermissions(Guid?userId)
{
使用(WikiTomeDataContext=新WikiTomeDataContext())
{
参数表达式CS$0$0001;
参数表达式CS$0$0003;
var permissions=context.Wikis.SelectMany(Expression.Lambda(Expression.Property(Expression.Constant(context),(MethodInfo)methodof(WikiTomeDataContext.get_VirtualWikiPageTags)),新参数Expression[]{CS$0$0001=Expression.Parameter(typeof(Wiki),“Wiki”)},Expression.Lambda(Expression.new((ConstructorInfo)methodof(f_uuu匿名类型8..ctor),新表达式[0],新方法信息[0]),新参数表达式[]{CS$0$0001=Expression.Parameter(typeof(Wiki),“Wiki”),CS$0$0003=Expression.Parameter(typeof(VirtualWikiPageTag),“pageTag”)};
返回null;
}
}
编辑3: 似乎确实有一个闭包类包含对DataContext的引用。以下是其反汇编代码:

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

    // Methods
    public <>c__DisplayClass1();
}
[编译生成]
专用密封c类显示器Class1
{
//田地
公共维基百科数据上下文;
//方法
公共c__DisplayClass1();
}

给出错误的代码使用WikiDataContext

您的两个没有给出错误的示例使用WikiTomeDataContext


这两个子句之间可能有一些差异导致了错误。

我的猜测是,这两个
From
子句在您的数据上下文上生成了一个对
SelectMany
的调用,并带有一个闭包。闭包的实例有一个指向datacontext的字段,它会导致FxCop警告。这没什么好担心的


datacontext只有一个实例,您可以通过using块清理它。因为闭包没有终结器,所以FxCop警告中没有性能或安全含义。

我注意到这是一个分部类。您是否检查了该类的其他实现文件并查看它是否有IDisposable m未被处理的余烬

我不认为生成的闭包是错误的。闭包是使用某些属性生成的,这些属性会导致FxCop忽略类似这样的警告

编辑

OP的进一步调查表明,这是一个问题,一个可识别的字段被取消关闭

不幸的是,您对此无能为力。无法使闭包实现IDisposable.Event。如果可以,则无法在闭包实例上调用IDisposable


解决此问题的最佳方法是重写代码,使一次性值不会在闭包中捕获。一次性字段应始终在完成后进行处理,并且在闭包中捕获字段会阻止您执行此操作。

如果您从方法返回LINQ查询,使用者将使用foreach检查结果

当使用者完成foreach循环时,它会在内部调用IEnumerable源上的dispose(在本例中是您的LINQ查询)。这将处理WikiTomeDataContext

但是,如果使用者调用了返回LINQ查询的方法,但从未对结果进行迭代,则enumerable似乎永远不会被处理(也就是说,直到垃圾收集器清理对象为止)。这将导致WikiTomeDataContext在垃圾收集之前不会被处理


解决此问题的一种方法是调用。要排列LINQ查询的结果,请在您的上下文中调用dispose,然后返回数组。

很好,但事实并非如此。我已编辑了我的问题,以使用一致的示例。这听起来很有道理。如果是这样,我需要采取某种措施吗为了确保DataContext被释放?没有什么可担心的。只有一个DataContext实例,您可以通过using块清理它。b/c闭包没有终结器,这里没有perf含义。如果我删除上述方法,FxCop不会生成错误。我还查看了r类,并且它似乎没有类级变量的任何IDisposable属性。@AaronSieb,很有趣。您是否检查了生成的闭包类以查看其成员是否实现了IDisposable@JaredPar我该怎么做?我对闭包的概念有点模糊…反汇编代码(通过.NET Reflector)如果有帮助的话,已经附加到我问题的末尾。@Aronsieb,看看类型WikiPage,里面应该嵌套了几个内部类型。它的名称DisplayClass在名称的两边都有看似随机的字符。这是“closure类”。@JaredPar closure类确实存在,但是没有