【问题标题】:c# type References (vs C)c# type References (vs C)
【发布时间】:2019-02-10 17:14:02
【问题描述】:

如果类是引用,则 c# 引用如何工作
class1 a = new class1();
所以名为“a”的地址包含 表示 mem[0] 的对象的地址,所以它是一个指针

为什么

method(class1 a);

将对象的值复制到本地方法实例而不是 mem[0] 的地址?
它是否隐式取消引用 (*) a? 如果是这样,那么ref修饰符取消它?

假设一个类定义了一种地址类型,以指向指向对象各个点的地址。我仍然无法完成它......

【问题讨论】:

    标签: c# pointers


    【解决方案1】:

    为什么method(class1 a) 将对象的值复制到本地方法

    这是一个错误的假设。方法参数a 包含对该对象的引用。如果您使用method(ref class1 a),那么您将获得对传递给方法的变量的引用,该变量又包含对对象的引用

    给定

    class1 a = new class1();
    method(ref a);
    

    在方法中,您可以为参数分配一个新对象,这将改变a

    void method(ref class1 b)
    {
        b = new class1(); // This changes a!
    }
    

    如果缺少ref 关键字,则该方法获取引用的副本(不是对象的副本!)

    void method(class1 b)
    {
        b = new class1(); // This does NOT change a.
    
        // But
        b.IntProperty = 5; // This changes a property of a.
    }
    

    在 C# 中,您不必使用 *。 C# 知道哪些类型是引用类型,哪些是值类型,并相应地对待它们。

    对于普通参数:

    • 对于值类型:传递值的副本。
    • 对于引用类型:传递值的副本(是的!)。该值恰好是一个引用(或null)。即,不会复制任何对象。

    对于ref参数:

    • 对于值类型:传递对包含该值的变量的引用。
    • 对于引用类型:传递对包含引用(或null)的变量的引用。

    也就是说,对于ref参数,参数名只是方法调用中使用的变量的别名。


    如果您觉得这很混乱,可以在编辑器中配置颜色以帮助区分引用类型和值类型。在 Visual Studio 中:转到菜单 Tools > Options...,然后 Environment > Fonts and Colors 并更改 User Types - Structures 的颜色(即值类型)以显示为与类不同的颜色(我使用的是 Olive )。还有一些其他的User Types 可以更改(我使用红色代表代表,深橙色代表枚举,紫色代表接口,一种霓虹绿色代表类型参数。

    【讨论】:

    • “对对象的引用是通过引用传递的”——我认为你把事情弄得太复杂了。对于所有ref 参数,无论是值类型还是引用类型,变量都是通过引用传递的。重要的是,它是指定为通过引用传递的参数的变量 - 而不仅仅是任何“对对象的引用”。如果有两个变量ab 的值恰好引用同一个对象,并且您调用Method(ref a),则该方法可以更改a 的值,但不能更改@987654345 的值@.
    • @JonSkeet,不容易解释(你在这门学科上要好得多)。我改写了我的答案。
    • 绝对更好。
    【解决方案2】:

    是的,从这个意义上说,您可能想将 C# 类变量视为(安全)C 指针。它们只是不允许您操纵它们在内存中指向的位置(甚至允许运行时重新分配和移动它们)。

    如果您的class1 是一个类类型(而不是结构类型或ValueType),那么您认为method 将复制整个a 对象是不正确的。相反,它会表现得好像你在 C 中传递了一个指针。但就像在 C 中一样,*p1==*p2p1==p2&p1!=&p2

    由于类变量只存储引用(类似于 C 指针),如果methoda 引用的对象进行了变异,这些变异将在method 返回后保留。通过 ref 传递一个类变量就类似于在 C 中传递一个指向指针的指针。但它在 C# 中几乎不可能是一个好的设计理念。

    这就是 class 变量的行为方式(包括字符串)。但是,也有一些值类型(除了字符串和对象以及结构之外的所有基本类型),它们在分配或传递给方法时会被复制,除非使用诸如 refout 之类的限定符传递。

    进一步阅读:

    【讨论】:

    • “类变量通过引用传递” - 不,它们不是。变量(引用)的值是按值传递的。说它们是通过引用传递的,意味着将 ref 添加到引用类型参数不会有任何区别,但事实并非如此。
    • “类类型的对象通过引用传递”也好不了多少。真的没那么复杂:引用类型变量的值是一个引用,而不是一个对象。对象根本不被传递:要么是通过值传递引用,要么是通过引用传递变量(对于ref 参数)。谈论通过引用传递的对象最终会变得更加复杂并且也会在空引用方面遇到麻烦。
    • 尝试更精确
    • 我的假设是错误的(课程误导了我)...方法(a)确实复制了名为“a”的地址的值
    【解决方案3】:

    您必须了解如何调用方法以及如何在内存中分配对象。

    所有类类型都是 C# 中的引用类型 - 继承自 System.Object

    支持 .NET Framework 类层次结构中的所有类,并且 为派生类提供低级服务。这是终极 .NET Framework 中所有类的基类;它是 类型层次结构。

    参考:MSDN Documentation of System.Object

    意思是,它们将被分配在堆中。他们的参考将被复制到某个地方。该变量保存引用被复制的位置。

    在方法调用的情况下,对象的地址被复制到调用堆栈。它指向同一个地址。

    因此,如果您更改类的任何属性(值类型),您仍然可以在调用方方法中访问更改后的值 - 即使您不使用 ref 关键字。

    void Method(Class A)
    

    从技术上讲, ref 关键字提供相同的地址位置 - 而不是将此地址复制到新位置。

    希望这能回答您的问题。

    【讨论】:

    • 我不知道你所说的“默认情况下,所有值都是 C# 中的引用类型”- 虽然我不明白,但我不知道我是否同意它。
    • 这仍然很奇怪 - 因为“默认情况下”表明类类型可能不是引用类型,但事实并非如此。
    • 绝对更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 2013-11-29
    • 2023-03-16
    • 2019-10-09
    • 2023-01-09
    • 1970-01-01
    相关资源
    最近更新 更多