【问题标题】:Why does this singleton behaviour occur?为什么会出现这种单例行为?
【发布时间】:2010-11-10 13:13:39
【问题描述】:

我的一个初级程序员创建了一个单例,但它的行为很奇怪:

我知道你不应该像这样访问对象,但他们就是这样做的,我无法解释为什么会发生这种情况 - 在调用 remove instance 之后,我在后面的行上放了一个断点,我仍然可以访问 someObject 对象及其属性。这种有意义,因为您访问 mySingleton 对象的引用,而不是 myInstance,...如您所见,我无法清楚地解释它,有人可以帮忙吗?

例如

    Dim x As MySingleton = MySingleton.GetInstance()

    x.someObject.int = 5
    x.someObject.str = "hello"

    Console.Out.WriteLine(x.someObject.int.ToString)
    Console.Out.WriteLine(x.someObject.str.ToString)

    MySingleton.RemoveInstance()

    Console.Out.WriteLine(x.someObject.int.ToString) //still exists!
    Console.Out.WriteLine(x.someObject.str.ToString) //still exists!

这是单例的伪代码:

Public Class MySingleton

    Private Shared _myInstance As MySingleton

    Public someObject As New Class1

    Public Shared Function GetInstance() As MySingleton
        If _myInstance Is Nothing Then
            _myInstance = New MySingleton
        End If
        Return _myInstance

    End Function

    Public Shared Sub RemoveInstance()
        _myInstance = Nothing
    End Sub


    End Class

就我个人而言,我不会像这样编写我的单例 - 我将实例对象作为一个单独的类。但每个人都有自己的。

【问题讨论】:

  • 重点:_myInstance 的用法不是单例,也不是线程安全的。特别是如果那是 ASP.NET(或任何其他高度线程化的环境),您将会遇到混乱。
  • 我忘了提 - 我希望在调用 remove instance 后会出现 null ref 异常...
  • @Marc - 是的,我知道,我已经简化了代码

标签: .net vb.net design-patterns language-agnostic


【解决方案1】:

这是因为您只删除了对象的MySingleton._myInstance 引用。

x 仍然有对该对象的引用。

编辑:
澄清一下:

是这样的:

var A = new Class();
var B = A;
A = null;
// Here B still has that reference to the created object

【讨论】:

  • 通过将 _myInstance 设置为空,现在不应该对该引用对象的所有引用都指向空吗?
  • 你说的我知道是真的,我不明白的是,如果我将 a.property 更改为某物,b.property 将自动等于它,因为它是指向对象的引用类型a...为什么名称不适用于将对象设置为空?
  • @Mr Shoubs,不,您并没有杀死该对象,只是删除了对该对象的句柄/引用。所有其他引用仍保留该对象。
  • @Mr Shoubs,不,他们为什么要这样做?假设我有一个具有 name 属性的员工对象,并且我执行 string empname =employee.Name;然后处置员工,您也想清除员工姓名吗?为了迂腐,字符串的不同之处在于赋值被重载并且字符串被实习,但重点仍然存在......
  • 顺便说一句,尽早掌握这一点很重要,因为当您遇到事件、lambdas 和内存泄漏时,找出仍然可以引用您的对象是唯一真正的解决方案!
【解决方案2】:

第一行获取对您的单例的引用,并且该引用将保持有效,直到对象被垃圾回收。但是,只要仍然存在对对象的引用,它就不会被垃圾回收 - 因此您将继续拥有对有效对象的引用,直到您将 x 显式分配给其他对象。

【讨论】:

  • 这是有道理的,-我刚刚注意到他将单例存储为成员变量
【解决方案3】:

一般来说,在 .NET 中,您永远不能明确/确定地将对象设置为空。您只能将其引用设置为 Nothing,然后允许垃圾收集器对其进行清理。如前所述,在您的原始代码中,您实际上通过将其分配给 x 来保留对它的引用。

一般来说,不建议将对象设置为 Nothing 或 null,因为对象在最后一次引用后符合垃圾回收条件;运行时注意到这一点。例如,如果您有这样的代码:

Dim anObject as new MyObject

anObject.DoAnOperation()
[1]
... 
...
'more code
...
...

Set anObject = Nothing
[2]

如果您没有将对象设置为 Nothing,则在点 [1] 之后的任何时间都可以进行收集。如果您这样做,则直到第 [2] 点才符合条件。如果您的方法需要很长时间才能完成,它可能会变得很重要。

更多信息:

http://msdn.microsoft.com/en-us/library/ee787088.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-31
    • 2018-07-27
    • 2014-06-07
    • 1970-01-01
    • 2016-11-27
    相关资源
    最近更新 更多