10

我正在为初学者阅读一本关于 C# 的书,我在“理解价值和参考”部分,但有些东西我不明白。我所看到的是,这些书试图向我解释这一点(我也在 Youtube 上的几个教程视频中看到了这种情况),该类被用来创建......一个对象(? ?) 的类。我已经阅读了发生这种情况的整个前一章,但我不太理解它,假设它会在下一章中变得更加清楚。它并没有变得更清楚,所以我认为在我理解我之前解释的东西的概念之前继续下去不是一个好主意。

以下部分是本书的一部分:

请记住,要初始化类等引用变量,您可以创建该类的新实例并将引用变量分配给新对象,如下所示:

Circle c = new Circle(42);
Circle copy = new Circle(99);
//Circle refc = c;
...
copy = c;

我可以用这个例子中的代码做什么,为什么它很方便?示例+解释将非常受欢迎。提前致谢!

4

11 回答 11

9

听它的声音,你还没有完全理解这本书的解释:

下面的内容是制作 2 个大小为 3 和 4 的圆圈,并复制第一个圆圈并将其设为 5 .. 除非您将其打印出来,否则它不是这样工作的。

class Program
{
    static void Main(string[] args)
    {

        circle a = new circle(3);
        circle b = new circle(4);
        circle d = a;
        d.Diameter = 5;

        Console.WriteLine("a is {0}", a.Diameter); // shows 5
        Console.WriteLine("b is {0}", b.Diameter); // shows 4
        Console.WriteLine("d is {0}", d.Diameter); // shows 5
    }
}

class circle
{
    public int Diameter;
    public circle(int d)
    {
        Diameter = d;
    }
}

因为你没有为d创建一个新的圈子,实际上d是a的别名,所以,就像某人的名字叫Peter一样,他也可以叫Pete。

于 2012-07-03T14:29:20.747 回答
5

请记住,要初始化类等引用变量,您可以创建该类的新实例并将引用变量分配给新对象[原文如此]

他展示了引用类型和值类型之间的区别。对于值类型,它已经被初始化。

double d;

你不必再做任何事情了。对于类或引用类型,您必须给它一个对象的实例。

Circle c;还没有分配给它的对象。

d = c.Radius 错误。引用不指向对象。内存访问冲突。

Circle c = new Circle();现在确实如此。

于 2012-07-03T14:33:54.057 回答
4

好吧,它可能很方便,但不一定总是很方便,可以为您的类型引用分配一个新对象的位置。在这种情况下,在最后一行copy = c;,您说 copy 现在指向c之前分配的内存位置,换句话说,在该行之后,它们都指向相同的内存位置。

于 2012-07-03T14:27:56.887 回答
3

为您提供面向对象编程的速成课程相当复杂,但这正是您目前所需要的:您目前需要了解OO 编程,这是一种编程范式,许多编程语言当然也有 C#。

您在上面的帖子中描述的问题如下:

oo-prgramming中,您正在编写由(大致)字段和方法组成的类。这些类具有静态字符,并且在您的应用程序开发期间存在(请不要与我在这里使用的静态一词和关键字“静态”混淆)。在应用程序运行期间,您可以使用这些静态*classes* 来创建这些类的对象,这意味着特定类可作为任意数量的完全相同的对象的构建计划。与类相比,这些对象也称为类的实例,并且仅在应用程序运行时存在。对象是动态的。

很短:当你上课时

class House {

// ...
}

你有一个房子的静态描述,你可以用它来创建动态的*对象*,即房屋。您正在使用所谓的new-operator执行此操作(使用 C# 和其他现代语言,如 Java) :

House house = new House();

您在这里所做的是声明一个 House 类型的变量。您使用类House自己定义的类型。就是这部分:

House house;

到目前为止,它只是一个 House 类型的变量,它什么都不做。这里重要的术语是它没有指向任何东西,这个没有东西被称为null

然后您可以使用以下语法创建此类的实例(动态对象):

house = new House();

现在您已经创建了一个对象并让变量 house 指向该对象。从现在开始,您可以使用变量 house 来引用这个对象。

我告诉你这是为了指出你在上面的帖子中提到的一个重要问题:值类型和引用类型的区别。

您在前面几行中所做的是创建了一个指向对象的新变量。这(大致再次)称为引用类型。与此相反,您拥有例如intbyteshort等原始类型。

int i = 4;

你再次声明一个变量。但是这次变量直接保存它的值而不是指向它。这称为值类型

值类型和引用类型之间的区别非常重要,例如当您将这些变量作为参数传递给方法时。

于 2012-07-03T14:46:09.397 回答
2

我会尝试修正那句话,因为那太糟糕了。

原来的:

请记住,要初始化类等引用变量,您可以创建该类的新实例并将引用变量分配给新对象,如下所示:

固定的:

请记住,要初始化引用类型的变量,您可以创建该变量类型的新实例并将变量更改为指向新对象,如下所示:

虽然为什么这应该是你应该记住的东西,但我不知道。是的,您可以创建对同一个对象的多个引用,这本身就很有用,但它并没有让我觉得它是一种特别有用的初始化策略。

修复得更好:

您可以使引用类型的变量引用同一个实例,但请记住变量本身不是别名,因此覆盖其中一个不会更改另一个。

于 2012-07-03T14:34:57.390 回答
1

您可以将类视为数据的模式,如规范或蓝图。当您使用“new”关键字时,您是在告诉计算机使用该蓝图为您制作一个对象。对象是该类的具体实例。

因此,如果您有一个蓝图(类定义),您可以调用 new 任意多次,以生成该类的任意数量的实例。就像你有一辆汽车的蓝图一样,你可以根据需要制作尽可能多的汽车副本(只要有足够的材料)。

这样做:

Circle c = new Circle(42);
Circle copy = new Circle(99);

告诉计算机使用 Circle 类定义并实例化两个对象(因此您的计算机内存中存在两个圆圈)。这些是具有不同属性的不同对象(一个半径为 42,另一个半径为 99)。它们被分配到变量 c 并复制。

复制代码的最后一行 = c; 是将变量c指向的圆放入变量副本中。

于 2012-07-03T14:35:26.807 回答
1

类定义是蓝图。把它想象成一个房子。每次你实例化一个对象时Circle c = new Circle(42),你都在用那个蓝图建造一座房子。每个房子在街道上都有一个地址(内存中的地址)。

你拥有的每一个变量都像一张纸条,上面列出了房子的地址。所以你在主街 123 号建了一座蓝色的 2 层房子,在一张纸上写下 123 主街,并在纸上标上“A”。接下来,您在 456 King Street 建造一座红色的 4 层房屋,并将地址写在纸上,并在纸上标上“B”标签。接下来,你拿到一张纸,写下你建造的第一栋房子的地址(123 Main Street),并在纸上标上“C”。

然后你去找画家,让他把房子漆成黄色。你给他纸条'C'。

在我们的示例中只有两个房子。由于 C 和 A “指向”同一个地址,它们现在指向一个黄色的房子。

House a = new House( blue, 2 );
House b = new House( red, 4 );
House c = a;
c.Color = yellow;
//Now a.Color is yellow as well
于 2012-07-03T14:40:31.773 回答
1

变量不是对象,它只是对对象的引用。因此,例如,在以下示例中,有两个变量都引用同一个对象:

Label label1 = new Label();
Label label2 = label1;
label1.Text = "1";
label2.Text = "2";

执行该代码后,您将看到label1.Text等于“2”而不是“1”。那是因为它们都引用了同一个Label对象,所以当你设置 时label2.Text,这两个变量都会改变。但是,如果您实例化了两个单独的标签对象,则结果会有所不同,例如:

Label label1 = new Label();
Label label2 = new Label();
label1.Text = "1";
label2.Text = "2";

在第二个示例中,每个变量都指向不同的Label对象(即 Label 类的不同实例)。因此,在运行此代码后,label1.Text将等于“1”并label2.Text等于“2”,正如您所期望的那样。

有充分的理由说明这两个选项都很重要并且可供您使用。例如,假设您要创建一个设置Texta 属性的方法Label,例如:

void SetLabelText(Label labelToSet)
{
    labelToSet.Text = "text";
}

您可以这样调用该方法:

Label label1 = new Label();
SetLabelText(label1);

在这种情况下,方法labelToSet中的变量SetLabelText将引用与变量相同的对象label1,因此当 'SetLabelText设置labelToSet.Text为“文本”时,它不是创建一个新的,它只是在作为参数传递给Label的现有对象上设置文本Label方法,这正是你想要发生的。

由于任何变量都可以设置为新对象或现有对象,因此在将其分配给对象之前将其视为“空”。正如我一开始所说,变量不是对象,它只是对对象的引用。如果一个变量根本没有引用任何对象(它是初始状态),那么null如果您尝试使用它,它将抛出异常。例如:

Label label1; 
label1.Text = "1";  // Throws a null reference exception

您可以根据需要声明任意数量的变量,但在null您实际实例化至少一个对象并将它们设置为该对象之前,它们都将保持不变。要实例化一个对象(即创建一个类的新实例),您必须使用new关键字(例如new Label())。

然而,到目前为止我所说的一切都只适用于“引用类型”(类)。“值类型”(结构)不是这种情况。当您将变量声明为值类型时,出于所有实际目的,它实际上是对象。许多简单的数据类型,例如int值类型。例如:

int x;
int y;
x = 1;
y = x;
y = 2;

运行上述代码后,xwill equal1ywill equal 2。设置y = x不会导致y引用与 相同的对象x。相反,它将值从 复制xy,从而创建一个新的值类型对象。

于 2012-07-03T14:42:34.270 回答
0

在您提供的示例中,与书籍提供的许多示例一样,您看到的是最基本的案例。在您真正深入了解代码之前,很难理解使用此类功能的最佳方式。

我不知道这是否完全正确,但我会使用这样的方式是:

private double GetArea(Circle c)
{
     //this will be a default circle should the passed in circle be invalid
     Circle toCalc = new Circle(5);

     //check to make sure c is valid
     if(c != null)
          toCalc = c;

     return Math.pow(toCalc.Radius, 2) * Math.Pi;
}

由于 toCalc 是一个类而不是原始数据类型,因此必须对其进行初始化才能编译代码。如果它没有被初始化,编译器会给你一些错误,比如“toCalc 可能没有被初始化”。

于 2012-07-03T14:36:23.553 回答
0

如果我们在这种情况下引用人类,则该类定义什么是人类以及它可以做什么(它的成员,如高度、宽度等,以及它的方法 eat()、drink() 等),并且一个对象代表实际的人类(一个叫安德鲁的人,高宽可以吃喝)

于 2012-07-03T14:33:22.200 回答
0

如果我错了,请纠正我,但是当我查看代码时,我看到正在创建两个对象,并且指向一个值是它们自己的内存位置。

副本 = c; 行只是说复制对象不会指向 c 对象的内存位置,而不是它最初设置的位置。

于 2012-07-03T14:34:52.180 回答