【问题标题】:Can you reference a reference?你可以参考参考吗?
【发布时间】:2013-06-05 17:16:52
【问题描述】:

您能否将引用传递给传递控件的引用类型?

我注意到,当您将控件传递给构造函数时,它实际上传递了对该控件的引用,然后如果您将另一个控件分配给该控件,它不会复制值,而是实际复制引用本身!为什么这不能用常规变量或至少用 ref 关键字来完成?

例如...

public class Test : Form
{

Test()
{
InitializeComponent();
}
Test_Load(object sender, EventArgs e)
{
new Test2((Control)MyTextBox).ShowDialog();
}

}

public class Test2 : Form
{
Public Control x_
Test2(Control x)
{
x_=x;
InitializeComponent();
}
//use x_ somewhere in code to actually change x
}

我不明白的是,这适用于控件,但不适用于其他变量。现在假设我将 x 作为 int ref 传递,我无法将 ref 本身传递给 x_?在控件的情况下,我什至不必使用 ref ,这让我很困惑这是如何发生的......我知道如何通过方法和父/所有者来回传递变量,所以我的问题非常具体特殊的准指针。也许我误解了传递 Control 的行为,如果是这种情况,您将如何构造一个 int 与 Control 完全一样,以便当您将一个 int 分配给一个像 Control 这样的 int 时,它会更改原始 int,就像它更改原始 Control 一样.

这行得通。发送与发送相同。

    new InputBox(((Label)sender)).ShowDialog();

    Label Send;
    public InputBox(Label send)
    {
     Send=send; 
    }

我希望它以同样的方式工作。发送现在与发送相同,但不完全相同。

    new InputBox(((string)sender)).ShowDialog();

    string Send;
    public InputBox(string send)
    {
     Send=send; 
    }

我知道如何在类等之间传递变量,但我特别要求让一个字符串的行为方式与 Label 在传递时的行为方式相同。当它被传递时,它就像一个指针一样传递,因为我可以使一个变量等于该变量的同一个实例。为什么我不能使字符串等于该字符串的同一实例?

【问题讨论】:

  • 您能否提供一个完整描述您的问题的代码(或伪代码),而不是从您的观点出发的代码?
  • 我添加了代码来说明我的意思。如果我声明 2 个变量并使用 Label 使一个变量相等,它将传递一个引用,但如果我使用一个字符串,它将传递一个值,而不是像 Label 这样的引用。

标签: c# ref


【解决方案1】:

我想你需要了解的是Value Types and Reference Types之间的区别

值类型

如果数据类型将数据保存在自己的内存中,则该数据类型是值类型 分配。

它们包括类型

  • 所有数值数据类型
  • 布尔值、字符和日期
  • 所有结构,即使它们的成员是引用类型
  • 枚举,因为它们的基础类型始终是 SByte、Short、Integer、Long、Byte、UShort、UInteger 或 ULong

参考类型

引用类型包含指向另一个内存位置的指针 保存数据。

它们包括类型

  • 字符串
  • 所有数组,即使它们的元素是值类型
  • 类类型,例如 Form
  • 代表

ref (C# Reference)更远

ref 关键字导致参数通过引用传递,而不是通过 价值。通过引用传递的效果是对 方法中的参数反映在基础参数中 调用方法中的变量。

这解释了为什么如果您希望将值类型的更改传播到 collung 方法,则需要更改方法签名以使用 ref。

这是一个关于构造函数调用的示例

Control c1 = null;
Class1 cl1 = new Class1(c1); //c1 is still null after this call
Control c2 = null;
Class1 cl2 = new Class1(ref c2); //c2 is NOT null after this call

class Class1
{
    public Class1(Control c)
    {
        c = new Control();
    }

    public Class1(ref Control c)
    {
        c = new Control();
    }
}

【讨论】:

  • 如果字符串和对象是引用类型,那么当我通过构造函数传递它时,它的行为就像值类型,但是当我通过构造函数传递控件时,它的行为就像指针/引用?我的意思是,如果您传递一个控件,它实际上的行为就像一个指针/引用,因为如果我创建另一个控件并使其等于该控件,它将在另一个表单上引用相同的确切控件。
  • @CodeCamper - 你是什么意思它表现得像一个值类型?
  • 我的意思是它的行为类似于引用类型。
  • @CodeCamper,我对此进行了测试,似乎所有传递给构造函数的参数都是按值传递的,除非明确指定为 ref。
  • 例如传递一个标签,它将作为参考传递。即使您将其分配给不同的标签变量。如果我通过标签 x 并分配 x_ = x,那么 x_ 将包含 x 所指的相同实体。所以它的行为就像一个指针。因此,如果我要同时更改 x 和 x_ ,它将更改内存中的相同地址。但是,如果我将标签装在对象中,它会神奇地决定将其作为值传递。
【解决方案2】:

我认为,.NET 中字符串的不变性会让您感到困惑。

字符串引用类型。
但它被设计为不可变

这意味着,您无法修改 System.String 的实例。每次你做任何应该修改字符串的操作时,它只会创建一个字符串的 new 实例。看看这个样本:

class A
{
    private string someString;

    public A(string someString)
    {
        this.someString = someString;
    }

    public string SomeString
    {
        get { return someString; }
    }

    public void DoSomething()
    {
        someString = someString + "_abc";
    }
}


var sampleString = "Hello, world!";
var a = new A(sampleString);

Console.WriteLine(a.SomeString == sampleString); // prints 'true'

a.DoSomething();

Console.WriteLine(a.SomeString == sampleString); // prints 'false'
Console.WriteLine(sampleString); // prints 'Hello, world!'
Console.WriteLine(a.SomeString); // prints 'Hello, world!_abc'

最初sampleStringA.someString 是相等的。

但在这一行之后:someString = someString + "_abc" 字段 A.someString 引用 另一个 字符串实例,因为 + 运算符创建了一个新实例,并且赋值运算符已将该实例分配给 @987654329 @。

System.String 的行为不能像 Label,因为 Label 是可变的。因此,Label.Text = "Foobar"; 不会创建新的标签实例。

UPD。 如果您想要一个可变字符串,它已经出现在 FCL 中。这是StringBuilder 班级。

【讨论】:

  • 我可以让 char[20] 表现得像 Label 吗?究竟是什么允许 x_=x 传递对标签的引用?假设我想创建自己的字符串数据类型,例如使用 Char[20] 以与 Label 相同的方式传递。
  • 我一直在使用 StringBuilder。是什么让 StringBuilder 能够作为引用传递而 int 例如不能作为引用传递?例如,假设我想做一个简化版的 int 或简化版的 string。究竟是什么让他们能够让多个变量名相等/引用内存空间中的相同值。 StringBuilder 不是在充当指针吗?
  • 我在个人资料上提出了一个新问题。因为这给我带来了一个新问题。究竟是什么让 String 设计为不可变的。代码中的什么允许等号神奇地创建一个新实例?如果没有您的知识类,我如何创建这些神奇的实例之一?当您对 StringBuilder 使用等号时,它会传递实例,但是当您对 String 使用等号时,它会神奇地创建一个新实例。
  • 我现在明白了,由于某种原因,我无法理解 String 的实例从未真正改变过的事实。我知道对 String 的每次更改都会创建一个新的 String,但我从没想过 String 的任何部分都不会发生任何变化。让我失望的一件事是编译器如何神奇地将 test="test" 转换为 test=new String("test") 我将其归因于我的额外困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多