【问题标题】:Is object a reference type or value type?对象是引用类型还是值类型?
【发布时间】:2013-07-14 10:14:16
【问题描述】:

我对@9​​87654321@仍有疑问。它是任何东西的主要基类,任何类。但它是引用类型还是值类型。或者喜欢这些行为中的哪一个呢?我需要澄清这一点。我很难理解。

     object obj1 = "OldString";
     object obj2 = obj1;
     obj1 = "NewString";
     MessageBox.Show(obj1 + "   " + obj2);
     //Output is  "NewString   OldString" 

在这种情况下,它就像一个值类型。如果对象是引用类型,那么为什么 obj2 的值仍然是“OldString”

   class SampleClass
    {
        public string Text { get; set; }
    }

    SampleClass Sample1 = new SampleClass();
    Sample1.Text="OldText";         

    object refer1 = Sample1;
    object refer2 = refer1;

    Sample1.Text = "NewText";

    MessageBox.Show((refer1 as SampleClass).Text +  (refer2 as SampleClass).Text);
    //OutPut is "NewText   NewText"   

在这种情况下,它的作用类似于引用类型

我们可以推断object 的类型就是你在里面装的东西。它既可以是引用类型,也可以是值类型。这是关于你在里面装的东西。我说的对吗?

【问题讨论】:

    标签: c# oop object value-type reference-type


    【解决方案1】:

    对象变量始终是引用类型。 类和字符串是引用类型。结构和枚举是一种值类型。 我从各种资源中整理了一个大例子。

    // PrintedPage is a value type
    //this is a struct
    struct PrintedPage
    {
        public string Text;
    }
    
    // WebPage is a reference type
    class WebPage
    {
        public string Text;
    }
    
    struct SampleClass
    {
        public string Text { get; set; }
        public override string ToString() { return Text; }
    }
    
    void Main()
    {
            // First look at value type behaviour
            PrintedPage originalPrintedPage = new PrintedPage();
            originalPrintedPage.Text = "Original printed text";
    
            // Copy all the information
            PrintedPage copyOfPrintedPage = originalPrintedPage;
    
            // Change the new copy
            copyOfPrintedPage.Text = "Changed printed text";
    
            // Write out the contents of the original page.
            // Output=Original printed text
            Console.WriteLine ("originalPrintedPage={0}",
                               originalPrintedPage.Text);
    
    
           //-------------------------------------------------------------------
            // Now look at reference type behaviour
            WebPage originalWebPage = new WebPage();
            originalWebPage.Text = "Original web text";
    
            // Copy just the URL
            WebPage copyOfWebPage = originalWebPage;
            // Change the page via the new copy of the URL
            copyOfWebPage.Text = "Changed web text";
    
            // Write out the contents of the page
            // Output=Changed web text
            Console.WriteLine ("originalWebPage={0}",
                               originalWebPage.Text);
    
            // Now change the copied URL variable to look at
            // a different web page completely
            copyOfWebPage = new WebPage();
            copyOfWebPage.Text = "Changed web page again";
    
             Console.WriteLine ("originalWebPage={0}",
                               originalWebPage.Text);
            Console.WriteLine ("copyOfWebPage={0}",
                               copyOfWebPage.Text);
    
    
           //-------------------------------------------------------------------
            //string are reference type too
             object obj1 = "OriginalString"; // create a new string; assign obj1 the reference to that new string "OriginalString"
             object obj2 = obj1;// copy the reference from obj1 and assign into obj2; obj2 now refers to // the same string instance
             obj1 = "NotOriginalString";// create a new string and assign that new reference to obj1; note we haven't // changed obj2 - that still points to the original string, "OriginalString"
            /*   When you do obj1 = "NewString"; it actually holds a new reference, to another memory location, not the same location you gave to obj2 before. 
               IMP -  When you change the content of the location obj1, you will get the same change in obj2.
            */
             Console.WriteLine(obj1 + "   " + obj2);
    
           //-------------------------------------------------------------------
             object onj11 = 2; 
             object obj12 = onj11;
             onj11 = 3; //you assigned boj11 to a new reference but obj12 reference did not change
             Console.WriteLine(onj11 + "   " + obj12);
    
           //-------------------------------------------------------------------     
             /*look below - it's possible for object to "reference" a value-type by the power of boxing. The box is a reference-type wrapper around a value, to which the object variable refers.*/
             int i = 2; //int is value type
             object j = i; //variable j is a reference to a box containing the value of i- but it's not i
             i = 3;  
             Console.WriteLine(i + "   " + j);       
    
           //-------------------------------------------------------------------
            var x = new SampleClass{ Text = "Hello" };
            object o = x;
            x.Text = "World";
            Console.WriteLine(x.Text + "   " + o);
    
           //-------------------------------------------------------------------
            SampleClass x1 = new SampleClass{ Text = "Hello" }; //sample class is of type struct which is value type; it is was of type class then the data would be copied over and result would be World World
            SampleClass o1 = x1;
            o1.Text = "World";
            Console.WriteLine(x + "   " + o);
        }
    

    参考资料 - http://jonskeet.uk/csharp/references.html

    【讨论】:

    • 感谢您的解释。真的很有启发性
    【解决方案2】:

    object 变量始终是引用类型。

    object 可以通过装箱的力量“引用”一个值类型。该框是一个值的引用类型包装器,object 变量所引用的值。

    int x = 10;     // a value-type
    object o = x;
    

    变量o 是对包含x 值的框的引用——但它不是x

    x = 20;
    MessageBox.Show( string.Format( "x:{0} o:{1}", x, o ) );
    

    这可能对可变值类型更有启发性:

    struct SampleClass
    {
        public string Text { get; set };
        public override string ToString() { return Text; }
    }
    
    var x = new SampleClass{ Text = "Hello" };
    object o = x;
    x.Text = "World";
    MessageBox.Show( string.Format( "{0} {1}", x, o ) );
    

    o 是对x 的加框引用,因此更改x 的值对o 没有影响。

    SampleClass 更改为类而不是结构(引用类型而不是值类型)会改变行为:object o = x; 行会使 o 引用与 x 相同的东西,并更改 x 的文本也会改变o的文字。

    【讨论】:

    • 史蒂夫解释得很好。所以在 int 的情况下,它正在创建包装器。但是,如果是 struct,则直接转换为 ref 类型。我对么?我只是想知道,为什么 .net 框架不遵循相同的技术?我的意思是,为什么 int 不能转换为 ref-type 或者为什么 struct 不能被包装器分配?
    【解决方案3】:

    当你这样做时

    obj1 = "NewString";
    

    它实际上持有一个 new 引用,指向另一个内存位置,而不是您之前给 obj2 的位置。当您更改位置obj1 的内容时,您将在obj2 中得到相同的更改。

    尝试用

    改变obj1的内容
    fixed(char* c = obj1 as string)
    {
        c = '0';
    }
    

    您的两个字符串现在都将是 "0ldString"

    这是因为对象是引用类型。

    【讨论】:

      【解决方案4】:

      它是一个引用类型

      用字符串做一个例子并不是很有启发性,因为字符串也是一个引用类型(很明显SampleClass也是);您的示例包含零“装箱”。

      如果对象是引用类型,那么为什么 obj2 的值仍然是“OldString”

      为什么不呢?当您创建 新字符串 时,不会将旧引用更改为指向新字符串。考虑:

       object obj1 = "OldString";
       // create a new string; assign obj1 the reference to that new string "OldString"
      
      object obj2 = obj1;
       // copy the reference from obj1 and assign into obj2; obj2 now refers to
       // the same string instance
      
       obj1 = "NewString";
       // create a new string and assign that new reference to obj1; note we haven't
       // changed obj2 - that still points to the original string, "OldString"
      

      【讨论】:

      • 使用字符串作为例子是一个非常糟糕的主意。 string 是参考,但它也是不可变的。当您创建一个新字符串时,它首先会查看字符串池,以查看是否已经存在类似的字符串。字符串是一个超级特例,不要用它来解释引用和值类型的概念。
      • "当你创建一个新的时,它首先会通过字符串池查看是否已经存在类似的字符串。" - 那是……不是真的。它会检查某些情况,但不会检查一般情况。至于为什么我首先使用字符串:因为问题是专门讨论字符串
      • 好的,我明白了,字符串是引用类型。但这与 int 类型相同。为第一个变量分配一个新的整数值不会改变另一个变量的值。这令人困惑。
      • @SinanILYAS 将新事物分配给变量 从不 改变旧事物的任何内容;我没有看到混淆 - 这里唯一的问题是:“事物是不可变的”,即我们可以在不替换整个事物的情况下更改事物的属性 of 吗?对于intstring,答案是“不,我们不能”——它们是不可变的。
      猜你喜欢
      • 2010-12-04
      • 2013-01-11
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      相关资源
      最近更新 更多