【问题标题】:Linkable variable type可链接变量类型
【发布时间】:2013-06-01 13:45:34
【问题描述】:

可以链接哪些变量类型?我曾尝试使用对象,但它没有达到我想要的效果。

object a;
object b;
b = 5;
a = b;
b = 2;
label1.Text = Convert.ToString(a);

它写的是 5,但我希望它是 2。

【问题讨论】:

  • 从阅读 MSDN 上的 Value Types and Reference Types 开始。
  • Boxing and Unboxing 将是一个很好的第二页阅读。
  • 尝试对 main 使用指针和不安全关键字
  • Value Types and Reference Types 中说“引用类型,例如对象”,那么对象是否是引用类型?
  • 但是,如果将值类型分配给 Object 变量,它的行为就好像它拥有自己的数据一样。 - 来自同一段落。

标签: c# variables ref


【解决方案1】:

这是对引用及其工作方式以及变量是什么的简单误解。

object a; // a is a storage location
          // it holds references to instances of object

object b; // b is a storage location
          //it holds references to instances of object

b = 5; // "boxes" 5 into an instance of object
       // and assigns reference to that object to b

a = b; // assigns reference in storage location b to storage location a

b = 2; // "boxes" 2 into an instance of object
       // and assign reference to that object to b

这样想。 ab 是一张纸,上面有住家的地址。当你说b = 5 时,可以把它想象成在一张纸b 上写下家庭地址5。当您说a = b 时,可以将其视为复制写在b 上的地址到a。当您说b = 2 时,请将其视为擦除写在b 上的地址,并将其替换为家庭地址2此操作不会更改写在纸上的值 a 这就是这里发生的情况。

现在,让我们看看一种非常简单的方法来让您尝试做的事情发挥作用。

class MyValue {
    public int Value { get; set; }
}

MyValue b = new MyValue { Value = 5 }; 
MyValue a = b;
b.Value = 2;

现在,如果你说

Console.WriteLine(a.Value);

会发生什么?让我们仔细推理。再次回到ab 的类比,它们是写有地址的纸片。我们已经说过MyValue b = new MyValue { Value = 5 }。可以将其想象为在纸上写下b 的地址,并在前门上方标有5 的标志。将a = b 视为复制写在b 上的地址到a。然后,将b.Value = 2 视为更改前门上方标志上的值,在本例中,将5 更改为2。现在,如果有人问,那张纸上写着地址a 的房子门上方的价值是多少?好吧,a 上的地址与b 上的地址相同。我们只是将前门上方标志上的值从5 更改为2。所以,我们希望看到2

试一试,你会看到2的值打印到控制台。

一遍又一遍地思考这个问题,直到你感觉到它深入骨髓。在您掌握这个基本概念之前,您会发现编程推理非常具有挑战性。

【讨论】:

  • 我可以链接两个没有数组的变量吗?
  • 也感谢您的回答:)
  • @halil12:如果您还有其他问题,请提出新问题。
【解决方案2】:

杰森的回答很好;添加更多内容:

您似乎期望当您说a = b 时,这意味着ab 现在是同一个变量的别名。这不是它的意思; a = b 表示将存储位置b内容复制到存储位置a,而不是重新标记存储位置a

然而一种使两个变量相互别名的方法;事实上,在 C# 中有 三种 方法可以做到这一点(除了 Jason 建议的技术,这可能是最好的)。

第一种方式是使用refout参数:

class P
{
    static object b = 5;
    static void M(ref object a) 
    { 
        b = 2;
        Console.WriteLine(a);
    }
    static void Main()
    {
        M(ref b);
    }
}

如果你运行它,你会看到它做你想做的事。 b5 开头,然后ref 表示ab 成为别名。当b改成2时,a也是因为他们是同一个变量有两个不同的名字。

但是,在单个方法中无法做到这一点。底层运行时确实支持这一点,我曾经制作了一个支持的 C# 版本:

object b = 5;
ref object a = ref b;
b = 2;
// now a is 2

但这从未成为交付给客户的语言版本。

另一种变量别名的方法只适用于高级程序员;您可以创建一个指针,在取消引用时为变量取别名:

int b = 5;
int* a = &b;
b = 2;
// Now *a is 2

请注意,指针类型只能为 int 等“非托管类型”的变量起别名,而不能为 object托管类型起别名。

我从事高级 C# 编程已有 10 年了,从来没有在生产代码中这样做过,所以如果我是你,我会避免这样做。

使一个变量别名为另一个变量的第三种方法仅适用于高级程序员;您可以使用 TypedReference 类型和 C# 的一些未记录的功能来捕获对变量的引用,然后稍后取消引用到别名。我的建议是不要使用此功能。

【讨论】:

  • 我只想再问一个问题。我可以将数组的元素作为 ref 发送吗?
  • @halil12:是的; any 变量可以通过ref 传递。数组元素是一个变量。你不能通过 ref 传递的一件事是 property;具有 getter 和 setter 的属性实际上不是变量。
【解决方案3】:
using System;

class Program
{
    static void Main(string[] args)
    {
        ValueTypeWrapper<int> a;
        ValueTypeWrapper<int> b;

        // The following line creates a new instance
        // of ValueTypeWrapper<int> by the means of
        // implicit conversion (see last method defined
        // in the ValueTypeWrapper<T> class).
        b = 5;

        // Make the variable "a" point to the same
        // ValueTypeWrapper<int> instance we just created.
        a = b;

        // Now that both variables are pointing to
        // the same *instance*, change the value of
        // the Value property.
        b.Value = 2;

        // Convert.ToString(...) will call
        // ValueTypeWrapper<int>'s ToString()
        // method, which in turn produces the
        // string equivalent of the value inside
        // the Value property.
        // The Value property is equal to 2
        // on both "a" and "b" objects as they
        // point to the same instance.
        Console.WriteLine(Convert.ToString(a));
        Console.ReadLine();
    }
}

public class ValueTypeWrapper<T> where T : struct
{
    public T Value { get; set; }

    public override string ToString()
    {
        return this.Value.ToString();
    }

    public static implicit operator ValueTypeWrapper<T>(T value)
    {
        return new ValueTypeWrapper<T> { Value = value };
    }
}

【讨论】:

  • 没问题。我喜欢它作为一个纯粹的学术练习。不过,您应该考虑将 Jason 的帖子标记为答案,因为他已经竭尽全力解释值和引用类型之间的差异 - 您应该仔细阅读并尝试吸收这些内容。
  • 稍微描述一下概念就好了。
猜你喜欢
  • 2022-10-18
  • 2021-01-01
  • 2011-07-19
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 2020-04-21
  • 2020-01-19
  • 1970-01-01
相关资源
最近更新 更多