【问题标题】:I really don't understand the reference of C#实在看不懂C#的参考
【发布时间】:2013-08-04 11:22:58
【问题描述】:

英语不是我的母语,我是中国人。如果我不能清楚地表达我的想法,我会很抱歉。

我以前用 c++ 编程。我真的不明白C#的参考。很多人告诉我 引用类似于c++中的指针。如下图

Person Foo = new Person(); // C#
Person *Foo = new Person(); // C++.

很多时候它运行良好。虽然许多 C# 编码人员也告诉我,类的实例只是 Foo.Foo 有 name.whiched 称为 Foo.name.Foo 有年龄,称为 Foo.age。看来 思想更容易用于编码。但是这种思想不符合Memory模型。

请告诉我 c# 中的引用是什么。一个对象,或者更可能是一个指针?谢谢。

【问题讨论】:

  • 在 C++ 中,使用. 访问对象的成员,-> 通过指针访问对象的成员,:: 访问静态成员。在 C# 中,您只需使用 . 即可。这并不意味着引用在某种程度上是“特殊的”。在引擎盖下它仍然只是一个地址(一个指针),该语言只允许您使用 . C++ 需要 ->

标签: c# reference memory-model


【解决方案1】:

您需要熟悉引用类型和值类型之间的区别。

示例如下:

void Main()
{
    Foo A = new Foo{Age = 16}; //A creates a space in memory for the data of Foo and points to that memory location
    Foo B = A; //B just creates a variable and points to the memory location created by A

    A.Bar();
    B.Bar();

    //Result
    //Your Age is 16
    //Your Age is 16

    A.Age = 24;

    A.Bar();
    B.Bar();

    //Result
    //Your Age is 24
    //Your Age is 24  <----- B is pointing to the same location as A and reflects the changes on call.

    FooValueType E = new FooValueType{Age = 23};
    FooValueType F = E;

    E.Bar();
    F.Bar();

    //Result
    //Your Age is 23
    //Your Age is 23

    E.Age = 56;

    E.Bar();
    F.Bar();

    //Result
    //Your Age is 56
    //Your Age is 23
}

public class Foo  //These object are by reference
{
    public int Age { get; set; }
    public void Bar()
    {
       Console.WriteLine("Your Age is {0}", Age);
    }
}

public struct FooValueType //These object are by value
{
    public int Age { get; set; }
    public void Bar()
    {
       Console.WriteLine("Your Age is {0}", Age);
    }
}

【讨论】:

    【解决方案2】:

    C# 具有垃圾回收功能,默认情况下不支持指针。但是,您可以使用此处列出的指针http://msdn.microsoft.com/en-us/library/t2yzs44b(v=VS.80).aspx

    【讨论】:

      【解决方案3】:

      关于可变行为,C#中有两种类型:

      • 值类型。
      • 参考类型。

      值类型变量携带实际对象作为它们的值。分配从另一个值类型变量分配的值类型变量复制整个对象。在 C++ 术语中,这就像使用类类型的变量(而不是指向类的指针),例如在创建堆栈分配实例时。然而,C# 并没有给您这种选择,而是将此行为限制为仅适用于结构等类型。

      引用类型变量携带对实际对象的引用作为它们的值。对实际对象的引用很可能至少涉及对象的内存地址(但细节对您隐藏)。从另一个引用类型变量分配一个引用类型变量复制的是引用,而不是对象,所以现在这两个变量指向同一个对象。在 C++ 术语中,这就像拥有一个类的指针变量。然而,对于类和接口等类型的变量,C# 默认采用这种行为(据我所知,没有办法跳回其他行为)。 C# 引用和 C++ 指针之间的主要区别在于 C++ 指针支持算术,而 C# 引用不支持。这是 C# 确保我们所谓的内存安全的方式之一。 (C# 确实提供了指针,但它们很少使用,而且很多时候它们在互操作性场景中很有用。可能需要很长时间才能在 C# 中使用指针。)

      最后,您可以认为 C# 引用接近于 C++ 指针(但是,如上所述,存在差异,因为语言的行为不同并为您提供不同程度的控制和保护)。

      【讨论】:

        【解决方案4】:

        在 C# 中当你说Person Foo = new Person();

        1. new Person() 通过在heap section 中分配内存来创建Person 类的对象
        2. 返回对这个 Person 类型对象的引用(即除了 reference to memory allocated)。

        当Foo 捕获此引用时,您可以使用此引用访问对象属性,即其methods and variables。

        在 C++ 中,

        它遵循相同的步骤,但在 c++ 中,您会在 pointer 类型的 Person 中捕获 reference to object。


        更具体地说,new 在内部调用operator new function 来分配memory dynamically 来创建对象。

        在下面显示的图像中,Person p (on stack) 创建了对new Person() 返回的对象的引用。

        age 和 name 是 Object 的成员变量。因此我们可以使用p.name 和p.age 轻松访问它们。


        更多关于 c# 和 c++ 中堆栈和堆内存分配的信息

        • 引用 Foo 总是在堆栈上获得内存
        • object 即此处new Person() 在堆上获取内存,在C# 的情况下更具体地说它在managed heap 上获取内存

        更新

        当您说new Person() 时,它在内部为类型为-person 的对象分配内存。该对象由Persons members 组成,如图所示。

        然后你可以做两件事

        1. 要么在Person 类型的变量中捕获此引用 例如Person p = new Person(); 这里p 是对对象内存位置的引用。因此我可以使用p 轻松访问Objects 成员。

        2. 只是不要存储引用直接使用它,例如 new Person().age 会给我人的年龄。这称为匿名对象。

        【讨论】:

        • 感谢您的回答。我可以理解内存模型。我很困惑的是对象什么都不做。如果我想访问对象,我必须使用引用。收到消息是参考
        • 似乎引用做了c++中对象所做的任何事情。那么我可以将对象的引用视为对象本身吗?这让我更容易理解。
        【解决方案5】:

        你在问之前用谷歌搜索过吗?互联网上有很多顶级资源,也有一些不错的电子书。

        但是,这里是 C# 中使用的内存模型(Java 和 PHP 中几乎一样):

        1. 每个对象都继承自类对象。这意味着,几乎所有东西都是 C# 中的对象。
        2. 您不再需要使用指针。在 C# 中几乎不需要它。当您创建一个对象时,您将获得对堆栈中实例的引用。您还可以对堆栈中的单个对象进行多次引用。引用位于堆中。这是默认行为,您无法更改它,除非您使用本机代码。
        3. 无需删除某些内容。这将由垃圾收集器自动发生。它将删除在方法末尾创建的每个局部变量。垃圾收集器还会删除不再引用的对象。
        4. 内部数据类型总是位于堆栈中,字符串也一样。对于字符串,他们在这里例外,字符串也被视为简单数据类型,而不是对象。
        5. 默认情况下,每个内部数据类型都将被复制,如果您 e. G。给方法一个 int 值。这种模式称为“按值调用”。每个对象都将由一个新的引用传递。这意味着,如果你给一个对象作为方法参数,你只会在方法内部获得一个对该对象的新引用。这种模式称为“Call-By-Reference”。这非常重要,您可以将它们分开。
        6. 您可以使用“ref”关键字将 Call-By-Value 更改为 Call-By-Reference。您也可以只定义一个 out 参数。这意味着,你给方法赋予什么价值并不重要。它只会在方法结束时返回一些东西。这可以通过在 C# 中使用“out”关键字来完成。
        7. 从逻辑上讲,您无法在 C# 中溢出堆。因为之前堆栈会溢出...
        8. 静态调用和对象调用之间没有区别了。它总是点。因此,您可以像调用类的公共静态成员一样调用类的公共成员。对于静态成员,你只需要使用类名,或者在类内变量名前不加任何关键字。您可以使用对它的引用来调用对象/类成员。
        9. 您只能从一个类继承。 C# 不支持多重继承(Java 和 PHP 也是如此)。
        10. Stdout 命令(>> 和 >)更改为“控制台”或任何其他流引用,例如。 G。文件输出流。

        编辑:

        子类继承基类的所有内容,包括私有和受保护的成员/方法。但您只能访问公共和受保护的成员/方法,除非您不使用反射。

        希望这可以帮助您进一步了解 C#...

        【讨论】:

          【解决方案6】:

          引用是指向对象的指针。

          您可以在不安全的代码中使用 C# 中的“真实”指针:here is an example

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-04-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-09-21
            • 2015-08-25
            • 1970-01-01
            相关资源
            最近更新 更多