代码之家  ›  专栏  ›  技术社区  ›  Safron

结构和接口中的C#getters/setter

  •  6
  • Safron  · 技术社区  · 8 年前

    我发现(根据我的说法)C#中结构和接口之间有一个奇怪的区别。考虑这个接口和结构:

    public interface INumber
    {
        void ChangeNumber(int n);
        void Log();
    }
    public struct Number : INumber
    {
        private int n;
        public void ChangeNumber(int n)
        {
            this.n = n;
        }
        public void Log()
        {
            Console.WriteLine(this.n);
        }
    }
    

    当我创建一个以Number为属性的新类时,使用ChangeNumber方法将n更改为2,并使用Log打印数字,它将打印0:

    public class NumberContainer
    {
        public Number Number { get; set; }
        public NumberContainer()
        {
            this.Number = new Number();
            this.Number.ChangeNumber(2);
            this.Number.Log();              //prints 0...
        }
    }
    

    过了一会儿,我意识到这是因为当我打电话的时候 this.Number.ChangeNumber(2); ,我实际上创建了一个新对象(因为getter),并将该数字更改为2。但随后我通过将number属性更改为INumber属性,对代码进行了一点更改:

    public class NumberContainer
    {
        public INumber Number { get; set; }
        public NumberContainer()
        {
            this.Number = new Number();
            this.Number.ChangeNumber(2);
            this.Number.Log();              //prints 2!
        }
    }
    

    在这种情况下,它打印2!为什么会发生这种情况?结构的相同原理不适用于接口吗?

    2 回复  |  直到 8 年前
        1
  •  4
  •   Community LiorH    7 年前

    不同的是 struct 用作值类型,其中 interface (可以由类或结构实现)是引用类型。

    这在你的例子中产生了巨大的不同。在第一种情况下,您在做什么 this.Number 意思是“给我数字的值”——这意味着它将值拉到堆栈上,而堆栈上的(未命名的)变量(没有存储在任何地方)将被修改。

    在另一种情况下,接口是一个引用类型——这意味着它获取存储在其地址上的任何内容并对其进行修改。

    一般来说,我不建议使用可变 结构 (如评论中已经提到的)。

    您可以阅读更多关于此主题的信息,例如: Why are mutable structs “evil”?

        2
  •  2
  •   csharpfolk    8 年前

    这是由中的auto属性引起的 NumberContainer 类,在访问属性时总是会得到值的副本。

    如果将属性更改为字段,它将按预期工作 。请记住,autoproperty只是一对方法,当返回/传递给任何方法时,都会复制值类型。

    当你打电话时

            this.Number.ChangeNumber(2);
            this.Number.Log();              //prints 0...
    

    您实际上正在呼叫:

     this.getNumber() // returns copy of value type
            .ChangeNumber(2); // executes op on that copy
    
        this.getNumber()
            .Log();
    

    当您使用接口时,您将返回对对象的引用,因此操作总是在同一对象上执行。