C# - 2个结构问题

时间:2010-06-19 12:59:07

标签: c# properties struct

我知道结构是值类型,但我不明白为什么这样有效:
编辑:我的意思是,为什么这个.Size.Height不起作用呢?

struct A
{
    int height;

    public int Height
    { 
        get
        {
            return height;
        }

        set
        {
            height = value;
        }
    }
}

//... class Main
{
    A a = A();
    a.Height = 5;  //works. Why? I thought it should say "cannot modify as it is not variable". I think the properties should return copy of this struct...?
}

第二个问题 - 我已经读过我不需要对结构使用“new”但是没有它对我来说它不起作用。

5 个答案:

答案 0 :(得分:6)

让我把它分解为几个问题:

  

什么是变量?

变量是包含值的存储位置。

  

为什么值类型称为值类型?

值类型变量的值是,并由复制。引用类型变量的值是引用,并由引用复制。这就是为什么值类型被称为值类型,而引用类型被称为引用类型。

  

为什么a.Height = 10有效?

要更改存储在引用类型变量中的值,您必须先拥有一个变量。在这种情况下,您可以:您拥有变量“a”。编译器将其编译为“将变量'a'的托管地址传递给具有参数10的高度设置器”。因此,Height属性setter知道如何找到存储在'a'中的值的位置并将其变异。

  

为什么a.Size.Height = 10不起作用?

要更改存储在引用类型变量中的值,您必须先拥有一个变量。表达“a.Size”不是变量;这是一个价值。 a.Size没有给你支持属性的变量 - 实际上,可能没有。相反,它为您提供了属性的价值。值类型按值复制;这是属性值的副本。这意味着编译器有两个选择:它可以将值复制到临时变量中然后改变该变量,诱使您认为您已经改变了a.Size的后备存储。或者,它可以给你一个错误,表明你正在做一些愚蠢的事情。它是后者。

  

这不是令人困惑和烦恼吗?

是。故事的寓意是不要制作可变的价值类型。仅生成不可变值类型。首先不要在值类型上设置setter;只在构造函数中进行赋值。如果事物必须是可变的,那么将它作为引用类型。

  

我是否必须使用“new”来创建值类型的新实例?

没有。您也可以使用“默认”:

Foo f = default(Foo);

如果Foo是一个值类型,那么这将使用Foo填充存储位置f的内容,Foo的所有字段都设置为默认值。

或者,如果值类型是可变的,则只需设置所有字段的值即可。但是,如果不使用构造函数或默认初始化程序,则必须设置所有。您必须设置所有包括私有字段

  

但是,如果某个结构体的所有公共字段都没有以两种方式违反最佳实践指南?首先,因为它有公共字段,第二,因为它是一个可变值类型?

是。不要那样做。

答案 1 :(得分:3)

我认为你将价值类型与不可变性混为一谈。我认为this SO question会对你有帮助。

答案 2 :(得分:1)

很正常。为什么你认为它不能让你为高度设定价值? 属性应该如何工作是非常正常的行为。 关于调用new,是的,它对于值类型不是强制性的。对于值类型,它只调用默认构造函数,它只是用默认值初始化字段。

答案 3 :(得分:1)

“this.Size.Height = 5”不起作用,因为当使用值类型作为属性的类型时,上面的代码行实际上意味着“this.get_Size()。set_Height(5)”,并且get_Size()调用的结果是原始的副本,是值类型。

因此,如果C#允许,将属性值设置为5将更改副本的值而不是原始属性值,这是非常不受欢迎的。

当然,当通过局部变量更改类的值类型属性时,这不适用,因此可以安全地支持此场景。

答案 4 :(得分:0)

属性将返回其“get”方法返回的值。结构和类是一样的。如果您提供“set”方法,它将执行“set”指示的任何操作。高度无法修改的唯一方法是使用私有“集合”,或者根本不提供“集合”。