什么是.NET对象生命周期?

时间:2009-06-15 10:29:44

标签: .net object

.NET中对象的对象生命周期是什么?

据我所知,它是:

  1. 创建对象 - 调用构造函数(如果存在)
  2. 使用的方法/属性/字段
  3. 对象销毁 - 处理被叫(如果存在)
  4. GC在某个时候调用的析构函数

9 个答案:

答案 0 :(得分:19)

Dispose不会自动调用;你需要调用它,或者使用一个使用块,例如

using(Stream s = File.OpenRead(@"c:\temp\somefile.txt"))
    // Do something with s

如果GC存在,则仅由GC调用终结器。使用终结器会导致您的课程分两步收集;首先将对象放入终结器队列,然后调用终结器并收集对象。没有终结器的对象直接收集。

指南是Dispose删除托管和非托管资源,终结器只清理非托管资源。当Dispose方法释放了非托管资源时,它可以调用GC.SuppressFinalize以避免将对象长时间放在终结器队列上。有关配置模式的正确样本,请参阅MSDN

答案 1 :(得分:17)

就像边缘情况一样......你可以在不使用ctor的情况下创建对象:

class Foo {  
    public Foo() {
        message += "; ctor";
    }
    string message = "init";
    public string Message { get { return message; } }
}
static class Program {
    static void Main() {
        Foo foo = new Foo();
        Console.WriteLine(foo.Message); // "init; ctor"
        Foo bar = (Foo)System.Runtime.Serialization.FormatterServices
            .GetSafeUninitializedObject(typeof(Foo));
        Console.WriteLine(bar.Message); // null
    }
}

答案 2 :(得分:6)

以下是我所知道的步骤:

  1. 加载程序集
  2. 执行静态初始化程序
  3. “新”电话:
    1. 分配内存
    2. 执行非静态初始化程序
    3. 执行构造函数
  4. 现在可以使用该实例
  5. 在对象的最后一次引用消失后:如果对象没有终结器,它现在可以收集;如果对象具有终结器,则将其置于终结器队列中。
  6. (可选)终结器队列中的对象在特殊线程中调用其终结器;如果应用程序仍然没有引用该对象,它现在也有资格进行垃圾回收
  7. 垃圾收集器释放内存
  8. 正如其他人已经指出的那样,Dispose()必须由用户调用,因为运行时不会对其起作用。

答案 3 :(得分:5)

Here是问题的详细描述。首先,Dispose不是由运行时调用的,你必须自己调用它。也没有析构函数,但是终结器:如果一个对象覆盖了Finalized方法,则在该对象不再可供应用程序访问时调用它。可能会发生在最终确定期间,对象再次可访问(例如,在全局对象中存储对自身的引用),因此它将返回到模型的第2步。 GC对象中还有一些方法可以让用户控制对象的最终化。

答案 4 :(得分:1)

关于构造函数的一点:

每个类都有一个,如果你不自己编写代码,编译器会生成一个。 这样做的第一件事(除非另有说明)是调用它的父类型的ctor。

答案 5 :(得分:1)

0)如果Object上存在Static Constructor,则第一次调用它,并且创建或引用该类型的对象

答案 6 :(得分:1)

这是一个示例类,它使用此处提供的文章中提供的所有信息。我已经花了几个小时测试一下,这对我来说最有效。

/*********************************
 * Author:  Theofanis Pantelides *
 *   Date:  23 Jun 2009          *
 *********************************/

using System;
using System.IO;

public class MyClass : IDisposable
{
    String oFile;
    Stream oStream;

    public MyClass(String _File)
    {
        oStream = File.OpenRead(oFile = _File);
        // Initialize
    }

    ~MyClass()
    {
        this.Dispose();
        // Destruct
    }

    public void doSomething()
    {
        // do Whatever it is you are trying to do
    }

    #region IDisposable Members

    /// <summary>
    /// Dispose all resources used by instance of class
    /// and update Garbage Collector information
    /// </summary>
    public void Dispose()
    {
        if (oStream != null)
        {
            oStream.Dispose(); // Dispose using built in functions
            GC.SuppressFinalize(oStream); // No need for Garbage Collector
        }

        oStream = null;  // Nullify it.
    }

    #endregion
}

用法:

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}

你甚至可以使用相同的声明两次,因为它不存在于'using'之外。

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}

答案 7 :(得分:1)

对象生命周期

创建对象:您使用 new 关键字来实例化新对象。

  1. 分配一块内存。这块内存足以容纳对象。 (CLR处理托管对象的内存分配)
  2. 将内存块转换为对象。该对象已初始化。 (您可以通过实现构造函数来控制此步骤)
  3. 销毁对象:您使用销毁来回收该对象使用的所有资源。

    1. 物体被清理干净;例如,通过释放应用程序使用的任何非托管资源,例如文件句柄和数据库连接。 (您可以通过实现析构函数来控制此步骤。)
    2. 回收对象使用的内存。
    3. CLR处理托管对象使用的内存释放;但是,如果使用非托管对象,则可能需要手动释放这些项目使用的内存。

答案 8 :(得分:0)

在C#中,成员初始值设定项在构造函数之前调用,而在VB.NET中,它们在构造函数之后调用。

运行时根本不保证调用Finalize

Dispose和Finalize仅用于清理 unmananged 资源。尝试通过例如清除终结器中的托管资源调用内部成员的处理会使你陷入困境,因为他们可能已经完成了。

我喜欢保持简单,只需使用终结器来检测并记录一条令人讨厌的错误消息,告诉开发人员修复代码。试图弄清楚是否可以安全地完成工作Dispose应该做的太容易出错,而且通常不值得花费时间。