我理解这个问题是否重复,但我在调整一些关于这个主题的帖子时遇到了一些麻烦.
首先是一点背景.我有一个类Foo如下
public class Foo : IDisposable
{
private Dictionary<int, string> _reallyBigDictionary =
new Dictionary<int, string>();
public void Dispose()
{
_reallyBigDictionary = null;
}
}
Run Code Online (Sandbox Code Playgroud)
已知Foo的实例范围有限(即我知道我们不会永远保持它).鉴于它的实例范围有限,我没有看到_reallyBigDictionary如何实际上比释放更快地释放内存.我理解它的方式,这些对象在运行垃圾收集之前不会被清除.那时,无论如何,对给定Foo实例的引用都将为null,因此我希望GC能够回收该内存.
这些帖子让我相信将成员变量设置为null没有意义:
这篇文章让我质疑: 正确使用IDisposable接口
任何人都可以为我澄清这一点吗?IDisposable实现在这里真的有必要吗?因为我无法说服自己.
编辑 - 根据答案重命名为终结器
我试图在终结器中做一些事情,但程序在我完成之前终止。为了模拟,我做了以下测试,最多打印 20
这是否意味着 .NET 终结器在 2 秒后“超时”?
~MyClass()
{
// do some cleaup
int i = 0;
while (true)
{
Console.WriteLine(i++);
Thread.Sleep(100);
}
}
Run Code Online (Sandbox Code Playgroud)
对于上下文,我有一些后台线程(任务对象),我想优雅地终止它们。我只是测试一下从终结器完成它需要多长时间。
有什么更好的设计模式可以做到这一点?也许有一个“关闭”方法,我必须确保在关闭表单时调用该方法?我知道终结器是为了清理非托管内存,但停止所有线程似乎很好,因为我知道它将被调用。
也许我只是让线程突然终止而不用担心?
我有一个像下面这样的功能:
Public Function testFunction(ByVal input_string As String) As String
Dim s As New StringBuilder()
Dim c As Char
For i As Integer = 0 To input_string.Length - 1
c = input_string.Chars(i)
s.Append(c)
Next
Return s.ToString
End Function
Run Code Online (Sandbox Code Playgroud)
但我想知道是否最好明确销毁任何对象,如下所示:
Public Function testFunction(ByVal input_string As String) As String
Dim s As New StringBuilder()
Dim c As Char
For i As Integer = 0 To input_string.Length - 1
c = input_string.Chars(i)
s.Append(c)
Next
Dim t As String = s.ToString
s = Nothing
Return …Run Code Online (Sandbox Code Playgroud) 是否有必要处理自定义对象,即使它们只包含托管对象?例如,我有一个包含一些List对象的自定义类,以及一些字符串和xmldocument类型.我应该创建自己的Dispose方法(不继承IDisposable)并清除它们以确保它们是空的吗?如果我应该,我还应该继承IDisposable吗?
这个问题基本上是我们GC.KeepAlive()首先需要的原因.
这就是我们需要它的地方.我们有一些非托管资源的包装器
public class CoolWrapper
{
public CoolWrapper()
{
coolResourceHandle = UnmanagedWinApiCode.CreateCoolResource();
if (coolResourceHandle == IntPtr.Zero)
{
// something went wrong, throw exception
}
}
~CoolWrapper()
{
UnmanagedWinApiCode.DestroyCoolResource(coolResource);
}
public void DoSomething()
{
var result = UnmanagedWinApiCode.DoSomething(coolResource);
if (result == 0)
{
// something went wrong, throw exception
}
}
private IntPtr coolResourceHandle;
}
Run Code Online (Sandbox Code Playgroud)
我们的代码使用该包装器:
var wrapper = CoolWrapper();
wrapper.DoSomething();
Run Code Online (Sandbox Code Playgroud)
如果此代码在Release配置中运行而不是在调试器下运行,那么代码优化器可能会发现在此代码之后实际上没有使用该引用coolResourceHandle,并且在读取内部后该成员变量未被访问(通过托管代码)DoSomething()并将其值传递给非托管代码,因此会发生以下情况:
DoSomething() 叫做coolResourceHandle 被读了~CoolWrapper() 运行UnmanagedWinApiCode.DestroyCoolResource() 运行并且资源被破坏,资源句柄无效UnmanagedWinApiCode.DoSomething() 使用现在引用不存在的对象的值运行(或者可能创建另一个对象并分配该句柄) …我有这样下面的代码来检索数据库数据,当我从Visual Studio中运行代码分析,它表明我调用Dispose方法SqlConnection,DataTable和SqlDataAdapter对象.
SqlConnection sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["connstr"].ConnectionString);
SqlCommand cmd = sqlconn.CreateCommand();
cmd.CommandText = "SELECT * FROM tbl_serial WHERE serial = @serial";
cmd.Parameters.AddWithValue("@serial", txtQuery.Text);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter();
try
{
sqlconn.Open();
da.SelectCommand = cmd;
da.Fill(dt);
}
catch (SqlException ex)
{
lblStatus.Text = ex.Message;
}
finally
{
sqlconn.Close();
}
if (dt.Rows.Count > 0)
{
lblStatus.Text = "FOUND!";
}
else
{
lblStatus.Text = "NOT FOUND!";
}
Run Code Online (Sandbox Code Playgroud)
这是我第一次这样做,我sqlconn就像这样调用dispose方法-
finally
{ …Run Code Online (Sandbox Code Playgroud) 可能重复:
正确使用IDisposable接口
我试图通过书籍,互联网和stackoverflow找到我的问题的实际答案,但到目前为止没有任何帮助我,所以希望我可以说明我的问题足够有意义.
一般来说,我总是找到与如何释放内存相同的基本用法,即约.如下,我确实理解代码本身:
public class MyClass : IDisposable
{
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Dispose(true);
GC.SuppressFinalize(this);
disposed = true;
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//free managed ressources
}
// free other ressources
}
~MyClass()
{
Dispose(false);
}
}
Run Code Online (Sandbox Code Playgroud)
它完全理解方法的工作方式.但现在我的问题是:为什么我们需要基类IDisposable?在此代码示例,我们定义了一个名为方法Dispose().当我到处读到该方法是IDisposable的一部分时,我们刚刚定义了该方法MyClass,如果我们不实现基类IDisposable或者我错误的假设,这段代码仍然有用吗?
我对C#并不是全新的,但我仍然需要学习很多东西,所以希望有人可以带领我朝着正确的方向前进.我检查了另一篇同样问题的帖子,但找不到它,所以如果它确实存在且它确实回答了我的问题,请带我到那里,我将删除这篇文章.
我最近一直在阅读关于IDisposable接口(这个主题非常有用,正确使用IDisposable接口)以及use语句的使用(主题在C#中使用"using").然后我开始想知道如果我应该以某种方式从内存中释放我自己的集合类.
class User{
private string username {set;get;}
private string password {set;get;}
...
}
Run Code Online (Sandbox Code Playgroud)
它应该实现IDisposable接口吗?
class User : IDisposable
{
...
public void Dispose()
{
this.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
所以它可以从内存中解放出来?或者GC是否自动完成,我甚至不应该为此烦恼.
据我所知,释放非托管资源(如数据库连接等)很重要,但这些集合类呢.因为我经常使用它真的开始让我烦恼.
TL;博士; 我应该在User类上实现IDisposable吗?
亲切的问候.
编辑:感谢大家的回复!
我已经阅读了很多文章,这些文章说 IDisposable 的目的是关闭非托管对象,如数据库连接和第三方报告。但我的问题是,如果我可以在我的方法中处理非托管对象而不定义 Dispose () 方法?
例如,
class Report : IDisposable
{
public void GenerateReport()
{
Report rpt=new Report() //unmanaged object created
rpt.Dispose(); // Disposing the unmanaged object
}
private void Dispose()
{
//not sure why this block is needed
}
}
Run Code Online (Sandbox Code Playgroud)
我的理解正确吗?
c# ×8
.net ×5
idisposable ×4
memory ×2
asp.net ×1
base-class ×1
dispose ×1
finalizer ×1
vb.net ×1