首页 > 解决方案 > 正在修改的其他类实例的属性

问题描述

我有一个类PageMaster,我为它实例化了几个实例,包括一个名为 EmptyPage 的实例,我从不写入(只读取)。

我还有其他类实例,例如 IndexPage、PrivacyPage 等。具有不同的属性集。

在我的程序(下面的代码)中,当我修改这些类实例中的任何一个时,每个其他实例也会以完全相同的方式进行修改。

Log3("Resetting special pages")

Log3("Setting pages equal to EmptyPage")
IndexPage = EmptyPage
PrivacyPage = EmptyPage
ContactPage = EmptyPage
AboutPage = EmptyPage
SiteIndexPage = EmptyPage
LogSpecialPages()

Log3("Setting flag IsIndexPage")
IndexPage.IsIndexPage = True
LogSpecialPages()

Log3("Setting flag isPrivacyPage")
PrivacyPage.IsPrivacyPage = True
LogSpecialPages()

Log3("Setting flag isContactPage")
ContactPage.IsContactPage = True
LogSpecialPages()

Log3("Setting flag isAboutPage")
AboutPage.IsAboutPage = True
LogSpecialPages()

Log3("Setting flag isSiteIndexPage")
SiteIndexPage.IsSiteIndexPage = True
LogSpecialPages()

Log3("Reset finished")

在我的程序的这个实际代码中,当我执行指令时,IndexPage.IsIndexPage = True每个页面实例 - PrivacyPage、ContactPage 等。都被修改了——不仅仅是IndexPage。同样的事情也发生在其他人身上。当我修改一个实例时,所有其他实例都更改了字符串和/或布尔变量值。

(为了进行日志记录,我使用 JSONConvert 序列化类实例并将其写入输出。)

我不明白为什么每个实例都被修改。这就是在我的表单类中实例化它们的方式:

Dim IndexPage As New PageMaster
Dim PrivacyPage As New PageMaster
Dim ContactPage As New PageMaster
Dim AboutPage As New PageMaster
Dim SiteIndexPage As New PageMaster
Dim EmptyPage As New PageMaster

我能想到的唯一可能的解释是,当我说 ,IndexPage = EmptyPage并将所有其他人分配为 EmptyPage 时,他们不知何故失去了他们的个人身份。不过,这对我来说没有意义,因为我从来没有发生过这样的事情。

该类非常简单,具有一些字符串和布尔属性。

然后我尝试了这个简单的修改。而不是IndexPage = EmptyPage我使用 IndexPage = New PageMaster它并且它工作正常。

这似乎证实,不知何故,将它们都设置为 EmptyPage 会混淆它们的标识。

为什么他们的身份会变得混乱,导致对一个实例进行任何更改?

这就像我说它IndexPage = EmptyPage只是创建一个从一个到另一个的符号引用,而不是我预期的行为,即将一个的所有属性设置为另一个的属性。

更新

在吉米的评论证实了我怀疑的情况之后,我决定做一个小测试。我只是在我的测试应用程序上放了一个按钮,并在其点击事件中添加了以下代码:

' PART 1:  STRING
Dim name1 As String = "Bob"
Dim name2 As String = "Larry"
name2 = name1
name2 = "Fred"
MsgBox(name1)

'PART 2: CUSTOM CLASS
Dim Bob As New Person
Bob.Name = "Bob"
Dim Larry As New Person
Larry.Name = "Larry"
Larry = Bob
Larry.Name = "Hubert"
MsgBox(Bob.Name)

在第一个示例中,我们得到了“Bob”的响应,这是我所期望的。

在第二个 msgbox 中,我们没有得到“Bob”。相反,我们得到了“Hubert”,因为类实例 Bob 现在指向 Larry,并且 Larry 的名字被更改为“Hubert”。

这促使我提出以下问题:

  1. 为什么使用 String 与我们自己创建的类的行为完全不同?
  2. 自定义类可以强制执行不同的行为吗?还是有另一种简单的方法可以将一个类的一个实例“复制”到另一个实例上?
  3. 这可能会延续到我也使用的 C# 中吗?

标签: vb.net

解决方案


关于您的更新:

为什么使用 String 与我们自己创建的类的行为完全不同?

它不是。完全一样。String和其他类型的唯一区别是String支持文字。在这段代码中:

Dim name1 As String = "Bob"
Dim name2 As String = "Larry"
name2 = name1
name2 = "Fred"
MsgBox(name1)

第四行没有改变所指String对象的某些内容。name2它正在为 分配一个不同的String对象name2。为什么你会期望它影响name1变量或String它所引用的对象?至于这段代码:

Dim Bob As New Person
Bob.Name = "Bob"
Dim Larry As New Person
Larry.Name = "Larry"
Larry = Bob
Larry.Name = "Hubert"
MsgBox(Bob.Name)

您还没有真正考虑过它的实际作用。在前四行之后,BobLarry指代两个不同的Person对象。第五行丢弃Larry引用的对象并将相同的Person对象分配给已经引用的对象。这两个变量现在都指向同一个对象。如果您通过一个变量对对象进行更改,那么您当然会通过另一个变量看到该更改。你怎么能不呢?LarryBobPerson

考虑这个现实生活场景。假设我和一个叫 Bob 的人是最好的朋友,而你和一个叫 Larry 的人是最好的朋友。你和拉里发生了争执,不再是朋友,你和鲍勃成了最好的朋友。你和我现在都是同一个人最好的朋友。如果你最好的朋友后来改名为休伯特,我最好的朋友会叫什么名字?应该是休伯特吧?这是非常明显的,那么为什么它在 OOP 中的工作方式是个问题呢?编程对象旨在模仿现实世界的对象,这就是为什么事情在 OOP 中与现实世界中的工作方式相同。

也可能引起混淆的一件事是String对象是不可变的,即一旦创建,它们就无法更改。这意味着,虽然您可以Person在第二个代码片段中更改对象的某些方面,但无法在第一个代码片段中更改String对象。如果你有一个类型的变量,String那么你可以为它分配一个不同的String对象——文字或表达式的结果——但你不能修改它所引用的对象。

自定义类可以强制执行不同的行为吗?还是有另一种简单的方法可以将一个类的一个实例“复制”到另一个实例上?

引用类型只有一种行为。所有引用类型的工作方式完全相同。如果要创建引用类型对象的副本,即类的实例,则必须创建它。需要这个的类通常会实现ICloneable接口,但您仍然需要自己提供实现。也就是说,人们认为他们不需要这种功能的情况并不少见。

这可能会延续到我也使用的 C# 中吗?

当然。面向对象就是面向对象。


推荐阅读