“使用”出现 CA2000 错误陈述。如何使这个有效?
以下代码给了我这个代码分析错误
CA2000:Microsoft.Reliability:在方法“SessionSummary.SessionSummary_Load(object, EventArgs)”中,在对象“实体”的所有引用超出范围之前调用 System.IDisposable.Dispose。
我正在使用“using”语句,所以我对此感到惊讶:
private void SessionSummary_Load(object sender, EventArgs e)
{
using (var entities = new DbEntities(Properties.Settings.Default.UserConnectionString))
{
entities.CommandTimeout = 7200;
var sessions = from t in entities.TableName
where t.UserSession.Id == _id && t.Parent == 0
group t by new { t.UserSession, t.UserSession.SessionId } into sessionGroup
select new
{
Id = sessionGroup.Key.UserSession,
Session = sessionGroup.Key.SessionId
};
summaryDataGridView.DataSource = sessions.Where(x => x.Time > 0.00);
summaryDataGridView.Columns[4].DefaultCellStyle.Format = "N2";
summaryDataGridView.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
}
}
The following code is giving me this code analysis error
CA2000 : Microsoft.Reliability : In method 'SessionSummary.SessionSummary_Load(object, EventArgs)', call System.IDisposable.Dispose on object 'entities' before all references to it are out of scope.
I am using a 'using' statement, so I am surprised on this:
private void SessionSummary_Load(object sender, EventArgs e)
{
using (var entities = new DbEntities(Properties.Settings.Default.UserConnectionString))
{
entities.CommandTimeout = 7200;
var sessions = from t in entities.TableName
where t.UserSession.Id == _id && t.Parent == 0
group t by new { t.UserSession, t.UserSession.SessionId } into sessionGroup
select new
{
Id = sessionGroup.Key.UserSession,
Session = sessionGroup.Key.SessionId
};
summaryDataGridView.DataSource = sessions.Where(x => x.Time > 0.00);
summaryDataGridView.Columns[4].DefaultCellStyle.Format = "N2";
summaryDataGridView.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您正在对
实体
执行LINQ样式查询,但实际上并未枚举using
块中的结果。这会产生关闭问题,因为存储在sessions.Where(x => x.Time > 0.00)
中的查询信息存储在summaryDataGridView.DataSource
中,并且存在因此,在上面的代码退出后,对仍在内存中的实体的引用。对此的解释是 LINQ 方法提供 延迟执行*,这意味着上面的代码中不会评估
session
和您分配给summaryDataGridView.DataSource
的值。要强制执行计算,您应该能够执行以下操作:
上面添加
ToList()
实际上会导致执行查询并将结果缓存在内存中。此外,实体将超出范围,并且您将不再通过任何闭包引用它;所以我相信这应该对你有用。*注意:这只是我从 Google 搜索中找到的第一个链接。不过看起来还不错。
You are performing a LINQ-style query over
entities
but are not actually enumerating over the result within theusing
block. This creates a closure issue, since the query information stored insessions.Where(x => x.Time > 0.00)
is being stored insummaryDataGridView.DataSource
and there is thus a reference toentities
still in memory after your code above exits.The explanation for this is that LINQ methods provide deferred execution*, which means that neither
session
nor the value you're assigning tosummaryDataGridView.DataSource
will be evaluated in the code above.To force evaluation, you should be able to do this:
The addition of
ToList()
above will actually cause your query to be executed and the results to be cached in memory. Furthermore,entities
will have gone out of scope and you will have no more references to it via any closure; so I believe that should do the trick for you.*Note: this was just the first link I found from a Google search. It looked pretty good, though.
实际上,您可能会过早处置,而不是较晚处置,因为参与分配给数据源的闭包的实体意味着它离开了范围。
你然后得到了一个在野外的实体,它不会在其真实范围内被处置,这正是分析所抱怨的,但与以下事实相比,这不太可能成为问题:它在最后一次使用之前被丢弃。
选项:
保持原样。如果上述方法有效,那么它可能是因为处置不会影响闭包工作的必要状态。这很冒险。押注“可能”并不是一个好主意,而且未来也可能会发生变化。 (我可以想到一种情况,在处理后使用对象是有意义的,但它很模糊,而且无论如何都不是您这里所拥有的)。
强制查询立即执行。对查询调用
ToList()
或ToArray()
将运行该查询并创建一个内存中结果,然后将该结果用作数据源。充其量,这在空间和时间上都会降低效率。最糟糕的是,情况可能会非常严重(取决于您正在处理的结果的大小)。确保控件在离开范围之前完成使用其数据源。然后清除数据源。根据所讨论的控件和其他一些问题(特别是,如果它有显式的 DataBind() 方法),执行此操作可能微不足道、不可能或介于两者之间。
将实体放入实例变量中。实现
IDisposable
。在您的Dispose()
方法中,调用它的Dispose()
方法。不要为此添加终结器,因为您只是处理托管对象。创建一个可枚举方法来包装查询(和使用),然后对查询返回的每个项目执行
yield return
。使用它作为数据源。对于大多数情况,5 似乎是最佳选择。它的优点是不会对代码进行太多更改,同时不会增加数字 2 的开销(可能很大,具体取决于数据)。请注意,只需调用
AsEnumerable
(它几乎具有对执行顺序的相同影响)不会产生相同的效果,因为闭包仍然会使块未执行。编辑:包装查询的枚举如下:
然后您将更改 SessionSummary_Load 设置为:
希望这能解决问题,因为
entities
永远不会离开using
的范围。You've actually got a potentially premature disposal, rather than a late one, as entities being involved in the closure assigned to the datasource means it leaves the scope.
You've then got an entities out in the wild that won't be disposed in its real scope, which is what the analysis is complaining about, but that's unlikely to be a problem compared with the fact that it is disposed before it is last used.
Options:
Leave it as it is. If the above works then it is probably because disposal doesn't affect the necessary state for the closure to work. This is dicey. Betting on "probably" isn't a good idea, and may also change down the road. (I can think of one case where using an object after disposal makes sense, but it's obscure and not what you have here anyway).
Force the query to execute eagerly. Calling
ToList()
orToArray()
on the query will run it and create an in-memory result that is then used as the datasource. At best though this will be less efficient in both space and time. At worse it could be cripplingly so (depending on the size of results you are dealing with).Make sure the control completes using its datasource before the scope is left. Then clear the datasource. Depending on the control in question and some other matters (in particular, if it has an explicit
DataBind()
method) it can be trivial, impossible or somewhere in between to do this.Put entity into an instance variable. Implement
IDisposable
. In yourDispose()
method, call it'sDispose()
method. Do not add a finaliser for this, as you are only disposing a managed object.Create an enumerable method that wraps the query (and the using) and then does a
yield return
on each item the query returns. Use this as the datasource.5 seems the best bet for most cases. It has the advantage of not changing the code much while not adding the (potentially large, depending on data) overhead of number 2. Note that just calling
AsEnumerable
(which has almost the same effect on execution order) would not have the same effect, as the closure would still be leaving the block unexecuted.Edit: An enumerable that wraps the query would be like:
Then you would set change SessionSummary_Load to:
Hopefully this will solve the problem, because
entities
never leaves the scope of theusing
.