结构变量如何存储在C#中

时间:2015-02-12 14:52:51

标签: c# struct

我读了这个StackOverflow Question 我读了这篇博客here

我无法完全理解。 这是我的疑惑。

 struct S
{
    private int x;
    private int y;

    public int X { get { return x; } }
    public int Y { get { return y; } }

    public S(int x, int y, bool panic)
    {          
        this.x = x;
        this.y = y;

        if (panic)
            throw new Exception();
    }
}

static class P
{
    static void Main()
    {
        S s = default(S);

        try
        {                

            s = new S(1, 2, false);

            Console.WriteLine("{0}, {1}", s.X, s.Y);

            s = new S(3, 4, true);
        }
        catch
        {
            Console.WriteLine("{0}, {1}", s.X, s.Y);
        }

        Console.ReadLine();
    }

}

在抛出异常之前我分配了值。但是为什么不分配给对象我的意思是在我在catch块中编写的控制台中, 说(1,2)。

因为它在第二行中再次初始化,并用(3,4)调用构造函数。怎么样(1,2)。

不知怎的,我无法理解这一点。

而且,

  

因此,在值类型上使用new运算符不会分配额外的内存。而是使用已为该值分配的内存。

在那篇博客中,答案是否定的。

如果是这种情况,是否使用新内存进行初始化。如果是这样,那么(1,2)是如何进入捕获区的。

由于我是C#的新手,我无法理解这一点。

我知道它的愚蠢怀疑,但有人请帮助我理解这个概念。

5 个答案:

答案 0 :(得分:4)

引自博客Debunking another myth about value types

  

C#规范在这一点上很清楚:

     

"如果T是结构类型,则通过分配临时局部变量来创建T的实例"

     

即声明

s = new S(123, 456);
     

实际上意味着:

     
      
  • 确定s。
  • 引用的位置   
  • 分配S类型的临时变量t,初始化为其默认值。
  •   
  • 运行构造函数,将对t的引用传递给"此"。
  •   
  • 制作t到s的副本值副本。
  •   

您在第三阶段抛出异常:

  
      
  • 运行构造函数,将对t的引用传递给"此"
  •   

意味着最后一个阶段,副本到s永远不会发生,因此您会看到s的当前值,在您的情况下为1, 2

答案 1 :(得分:2)

  

因为它在第二行再次初始化,并用(3,4)调用构造函数。

您已经调用了构造函数,但构造函数本身尚未完成 - 因此永远不会对s进行分配。

这个:

s = new S(3, 4, true);

等同于:

// Create the new value
S tmp = new S(3, 4, true);
// Copy it into the s variable
s = tmp;

第一个语句永远不会完成,因此分配不会发生...所以你仍然会在s块中看到catch的第一个值。

答案 2 :(得分:0)

在控制台中打印s.X和s.Y.这是

中的第一个
s = new S(1, 2, false);

永远不会执行第二个赋值,因为抛出了异常。

答案 3 :(得分:0)

在分配给等号左侧的S之前发生异常。

所以你的catch块会写出前一个赋值的原始值。

Capital S变量是Type,小s是实例。

答案 4 :(得分:0)

结构构造函数实现为将结构构造为隐含ref参数的方法。在许多情况下,编译器将实现如下语句:

s = new StructType(4);

等同于

var temp = default(StructType);
StructType..ctor(out temp, 4);  // Not possible with C# syntax
s = temp;

但是,有些情况下它没有这样做,而只是这样做:

StructType..ctor(out s, 4);

并且可以观察到这种情况,特别是当与其他语言编写的代码进行交互时,C#用于标记out参数。

例如,虽然无法在C#中编写IDictionary.TryGetValue的实现,但不会将default(TValue)存储到其out参数中,但该参数将被其他参数看到语言为ref参数;因此,用另一种语言编写的实现可能会返回而不会向其写入任何内容。如果结构构造函数将this传递给传入的TryGetValue的{​​{1}}方法,但不执行任何其他操作,则可以观察到结构构造的实际行为。