- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用一个在其构造函数中使用对 EF 的引用的类。
我已经实现了 IDisposable
,但我不确定是否需要析构函数,因为我不确定是否可以将 EF 归类为非托管资源。
如果 EF 是托管资源,那么我不需要析构函数,所以我认为这是一个合适的示例:
public ExampleClass : IDisposable
{
public ExampleClass(string connectionStringName, ILogger log)
{
//...
Db = new Entities(connectionStringName);
}
private bool _isDisposed;
public void Dispose()
{
if (_isDisposed) return;
Db.Dispose();
_isDisposed= true;
}
}
如果 EF 是非托管的,那么我会这样做:
public ExampleClass : IDisposable
{
public ExampleClass(string connectionStringName, ILogger log)
{
//...
Db = new Entities(connectionStringName);
}
public void Dispose()
{
Dispose(true);
}
~ExampleClass()
{
Dispose(false);
}
private bool _isDisposed;
protected virtual void Dispose(bool disposing)
{
if (_isDisposed) return;
// Dispose of managed resources
if (disposing)
{
// Dispose of managed resources; assumption here that EF is unmanaged.
}
// Dispose of unmanaged resources
Db.Dispose();
_isDisposed = true;
//freed, so no destructor necessary.
GC.SuppressFinalize(this);
}
}
是哪一个?
最佳答案
在这种情况下,您绝对不想使用终结器(析构函数)。
是否DbContext
是否包含非托管资源,甚至是否负责任地释放这些非托管资源,都与您是否可以尝试调用 DbContext.Dispose()
无关。来自终结器。
事实是,任何时候您有一个托管对象(DbContext
的一个实例),从不尝试调用任何方法都是安全的在那个例子上。原因是,在调用终结器时,DbContext
对象可能已经被 GC 收集并且不再存在。如果发生这种情况,您将得到 NullReferenceException
。尝试调用 Db.Dispose()
时.或者,如果你幸运的话,Db
仍然“活着”,也可以从 DbContext.Dispose()
中抛出异常方法,如果它依赖于已经完成和收集的其他对象。
因为这个"Dispose Pattern" MSDN article说:
X DO NOT access any finalizable objects in the finalizer code path, because there is significant risk that they will have already been finalized.
For example, a finalizable object A that has a reference to another finalizable object B cannot reliably use B in A’s finalizer, or vice versa. Finalizers are called in a random order (short of a weak ordering guarantee for critical finalization).
另外,请注意 Eric Lippert 的 When everything you know is wrong, part two 中的以下内容:
Myth: Finalizers run in a predictable order
Suppose we have a tree of objects, all finalizable, and all on the finalizer queue. There is no requirement whatsoever that the tree be finalized from the root to the leaves, from the leaves to the root, or any other order.
Myth: An object being finalized can safely access another object.
This myth follows directly from the previous. If you have a tree of objects and you are finalizing the root, then the children are still alive — because the root is alive, because it is on the finalization queue, and so the children have a living reference — but the children may have already been finalized, and are in no particularly good state to have their methods or data accessed.
需要考虑的其他事项:您要处理什么?您是否关心确保及时关闭数据库连接?如果是这样,那么您会对 EF documentation 的内容感兴趣。不得不说:
By default, the context manages connections to the database. The context opens and closes connections as needed. For example, the context opens a connection to execute a query, and then closes the connection when all the result sets have been processed.
这意味着,默认情况下,连接不需要 DbContext.Dispose()
被要求及时关闭。它们在执行查询时打开和关闭(从连接池)。所以,尽管确保你总是调用 DbContext.Dispose()
仍然是一个很好的主意。明确地说,了解这一点很有用,如果您不这样做或出于某种原因忘记了,默认情况下,这不会导致某种连接泄漏。
最后,您可能要记住的最后一件事是,您发布的代码没有终结器,因为您实例化了 DbContext
。在另一个类的构造函数中,DbContext.Dispose()
实际上是可能的方法不会总是被调用。了解这种特殊情况是件好事,这样您就不会被束之高阁。
例如,假设我稍微调整了您的代码以允许在构造函数中实例化 DbContext
的行 后抛出异常。 :
public ExampleClass : IDisposable
{
public ExampleClass(string connectionStringName, ILogger log)
{
//...
Db = new Entities(connectionStringName);
// let's pretend I have some code that can throw an exception here.
throw new Exception("something went wrong AFTER constructing Db");
}
private bool _isDisposed;
public void Dispose()
{
if (_isDisposed) return;
Db.Dispose();
_isDisposed= true;
}
}
假设你的类是这样使用的:
using (var example = new ExampleClass("connString", log))
{
// ...
}
尽管这看起来是一个非常安全和干净的设计,因为在 ExampleClass
的构造函数中抛出了一个异常。 在 DbContext
的新实例之后已经创建,ExampleClass.Dispose()
永远不会被调用,并且推而广之,DbContext.Dispose()
永远不会在新创建的实例上调用。
您可以阅读更多关于这种不幸情况的信息 here .
确保DbContext
的 Dispose()
方法总是被调用,无论 ExampleClass
内部发生什么构造函数,则必须修改 ExampleClass
类是这样的:
public ExampleClass : IDisposable
{
public ExampleClass(string connectionStringName, ILogger log)
{
bool ok = false;
try
{
//...
Db = new Entities(connectionStringName);
// let's pretend I have some code that can throw an exception here.
throw new Exception("something went wrong AFTER constructing Db");
ok = true;
}
finally
{
if (!ok)
{
if (Db != null)
{
Db.Dispose();
}
}
}
}
private bool _isDisposed;
public void Dispose()
{
if (_isDisposed) return;
Db.Dispose();
_isDisposed= true;
}
}
但是如果构造函数不仅仅是创建一个 DbContext
的实例,那么以上内容实际上只是一个问题。 .
关于c# - 我应该将 Entity Framework 视为非托管资源吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31833599/
将“”转换为“>”的主要目的是避免以下内联脚本: var foo = "alert('bug');"; // the value of foo is generated from server
我有以下想法: 在德语中我们有四个额外的字母(ä、ö、ü、ß),我不知道任何其他语言有这些声音,但我认为有口音的法国人也知道这个问题。我们在 Google Play 商店中有很多适用于城市、公交车站、
#!/bin/bash read nameArg find -name "$nameArg" 使用此代码,当我输入例如 *.txt 时,它将为我提供以 txt 结尾的所有文件,但我只想要名称为 *.t
我在 MySQL 5.7.27 中有一个带有 utf8mb4_unicode_ci 排序规则的用户表。 不幸的是, ı 没有像 i 那样进行线程化,例如,以下查询将找不到 Yılmaz select
我的简单 MySQL 查询: SELECT `word` FROM `nouns` WHERE `word` LIKE 'vandenys' 返回: vandenis 但是“vandenYs
虽然我以前用过这样的代码,而且很明显编译器有足够的信息可以工作,但我真的不明白为什么会这样编译: template auto foo(const T& t, I i) { return st
如何实现一个以 int 开头的函数,并在每次(经历有限数量的可能性)返回 1 的几个(例如,5 个) bool 值之一时从中减去 1。 理想情况下的外观是: function list1 list2
因此,如果我的数据库中有一个包含值的表 1 2 3 4 NULL 我执行了查询 SELECT MAX(col1) FROM 我会得到 4。有什么办法可以改变这个,所以 Null 将被视为最大值而不是
例如:我在数据库中有一条记录:[Example] Attena Illusive - 01 [720p].mkv尝试使用查询进行搜索: SELECT ts_rank_cd(to_tsvector('
我试图创建 2 个简单的盒子,并允许用户从 1 个盒子中选择数据,然后将其复制到第二个盒子。如果第二个框中已经有相同的文本,请在后面附加一些简单的文本。 它基本上在该项目不在第二个框中时起作用。但是,
这个问题已经有答案了: How to read a file from jar in Java? (6 个回答) 已关闭10 年前。 我想从我的 *jar 存档中读取文件。我在互联网上阅读了如何从 z
我在 Javascript 中偶然发现了一个我无法理解的极其奇怪的事件。 这是一个非常简单的 if 语句: let hours = 20; 我在这里设置了一个断点,并在调试器中设置了hours = 0
这两个查询给出了完全相同的结果: select * from topics where name='Harligt'; select * from topics where name='Härligt
我有一个包含数值和 NaN 的表格。求和时,如果所选值包含 NaN,则结果将为 NaN。有没有办法让 postgresql 在求和时将它们视为 0 而不是 NaN?或者我只需要将表中的所有 NaN 转
我有一个正在构建的页面,我希望当我滚动(向上或向下)页面时滚动到下一个 div(每个 div 是窗口高度的 100%)。并在那里“固定”,直到您再次滚动。可以在此处看到我正在努力完成的示例: http
我正在用 Javascript 制作一个小的 HTML 页面。它不需要服务器端,但我需要存储这个人所做的事情,所以我正在使用 localStorage。( list ) 如今,浏览器可以选择不存储 c
这两个查询给了我完全相同的结果: select * from topics where name='Harligt'; select * from topics where name='Härligt
我想向 Lua 公开一些 C++ 类。我可以调用Widget:New()获取带有元表集的返回用户数据到表 WidgetMeta . WidgetMeta包含所有 C++ 函数,它是 __index设置
我正在使用一个大型的旧数据库,现在我尝试使用 hibernate 而不是 SQL 来访问它。更大的问题之一是在外键中无限制地使用“0”和“-1”(意思是“NULL”)。 我生成了很多代码,但我手动添加
我试图将一个数字传递到一个 BYTES 数组中 - 但将该数字视为一个字符数组。这是我的代码: for(int i=1;i<=totalFiles;i++) { BYTE* input = n
我是一名优秀的程序员,十分优秀!