C# 在C中指定这个关键字#

C# 在C中指定这个关键字#,c#,.net,memory,specifications,C#,.net,Memory,Specifications,主要问题是,允许修改this关键字对有用性和记忆有什么影响;为什么C语言规范中允许这样做 如果选择回答,则可以回答或不回答其他问题/子部分。我认为对这些问题的回答将有助于澄清主要问题的答案 我无意中发现了这一点,以此作为回答 我一直在想为什么C语言规范会允许这样做子部分1。是否有任何东西可以证明此是可修改的?它有用吗 对该答案的评论之一是 从CLR通过C#:他们这样做的原因是因为你 可以在另一个结构中调用结构的无参数构造函数 构造器。如果只想初始化结构的一个值 如果希望其他值为零/空(默认值),

主要问题是,允许修改this关键字对有用性和记忆有什么影响;为什么C语言规范中允许这样做

如果选择回答,则可以回答或不回答其他问题/子部分。我认为对这些问题的回答将有助于澄清主要问题的答案

我无意中发现了这一点,以此作为回答

我一直在想为什么C语言规范会允许这样做子部分1。是否有任何东西可以证明此是可修改的?它有用吗

对该答案的评论之一是

从CLR通过C#:他们这样做的原因是因为你 可以在另一个结构中调用结构的无参数构造函数 构造器。如果只想初始化结构的一个值 如果希望其他值为零/空(默认值),则可以编写public Foo(intbar){this=newfoo();specialVar=bar;}。这不是 高效且不真正合理(specialVar分配两次),但 仅供参考。(这是书中给出的理由,我不知道我们为什么 不应该只做公共Foo(int-bar):this())

第2部分。我不确定我是否遵循了这个推理。有人能澄清他的意思吗?也许是如何使用它的一个具体例子

编辑(忽略堆栈或堆的要点与内存释放或垃圾回收有关。可以用262144个公共int字段替换int[]而不是int[] 根据我的理解,如果这个结构有一个1 Mb字节的数组字段,那么结构是在堆栈上创建的,而不是在堆上创建的

public int[] Mb = new int[262144];
第3子部分。调用Foo时是否会将其从堆栈中删除?在我看来,由于结构从未超出范围,因此它不会从堆栈中删除。今晚没有时间创建一个测试用例,但也许明天我会为这个做准备

在下面的代码中

Teaser t1 = new Teaser();
Teaser tPlaceHolder = t1;
t1.Foo();
子部分4。t1和tPlaceHolder是否占用相同或不同的地址空间

很抱歉提出一个3年前的帖子,但这篇帖子真的让我头疼

仅供参考,关于stackoverflow的第一个问题,所以如果我在这个问题上有什么问题,请发表评论,我将进行编辑


两天后,我将在这个问题上悬赏50英镑,即使我已经在脑海中选择了一个获胜者,因为我认为答案需要合理的工作量来解释这些问题

具有此可分配性允许使用结构的“高级”角落案例。我发现的一个例子是交换方法:

struct Foo 
{
    void Swap(ref Foo other)
    {
         Foo temp = this;
         this = other;
         other = temp;
    }
}
我强烈反对这种用法,因为它违反了结构的默认“期望”性质,即不可变性。可以说,有这一选择的原因尚不清楚

现在,当涉及到结构本身时。它们在以下几个方面与班级不同:

  • 它们可以存在于堆栈上,而不是托管堆上
  • 它们可以封送回非托管代码
  • 不能将它们分配给空值
有关完整概述,请参阅:

与您的问题相关的是,您的结构是位于堆栈还是堆上。这由结构的分配位置决定。如果结构是类的成员,它将在堆上分配。否则,如果直接分配一个结构,它将被分配到堆上(实际上这只是图片的一部分。一旦开始讨论C#2.0中引入的闭包,整个过程将变得相当复杂,但现在它足以回答您的问题)

NET中的数组默认分配在堆上(使用不安全代码和stackalloc关键字时,此行为不一致)。回到上面的解释,这表明struct实例也在堆上分配。事实上,证明这一点的一个简单方法是分配一个1 mb大小的数组,并观察如何不引发stackoverflow异常

堆栈上实例的生存期由其作用域决定。这与管理器堆上的实例不同,该实例的生存期由垃圾回收器确定(以及是否仍然存在对该实例的引用)。您可以确保堆栈上的任何内容只要在作用域内都有效。在堆栈上分配实例并调用方法不会取消分配该实例,直到该实例超出范围(默认情况下,当声明该实例的方法结束时)

结构不能有指向它的托管引用(非托管代码中可以有指针)。在C#中处理堆栈上的结构时,基本上有一个指向实例的标签,而不是引用。将一个结构分配给另一个结构只是复制基础数据。您可以将引用视为结构。简单地说,引用只不过是一个包含指向内存中某个部分的指针的结构。将一个引用指定给另一个引用时,指针数据会被复制

// declare 2 references to instances on the managed heap
var c1 = new MyClass();
var c2 = new MyClass();

// declare 2 labels to instances on the stack
var s1 = new MyStruct();
var s2 = new MyStruct();

c1 = c2; // copies the reference data which is the pointer internally, c1 and c2 both point to the same instance
s1 = s2; // copies the data which is the struct internally, c1 and c2 both point to their own instance with the same data

首先,我认为你应该先检查一下你问的问题是否正确。也许我们应该问,“为什么C#不允许在结构中对
这个
赋值?”

在引用类型中指定
this
关键字有潜在危险:您正在覆盖对正在运行的对象方法的引用;您甚至可以在初始化该引用的构造函数中这样做。现在还不清楚这种行为应该是什么。为了避免必须弄清楚这一点,因为它通常没有用处,所以规范(或编译器)不允许这样做

但是,在值类型中为
这个
关键字赋值是有明确定义的。赋值类型是一种复制操作。每个字段的值从赋值的右侧到左侧递归复制。这是一次非常安全的手术
// declare 2 references to instances on the managed heap
var c1 = new MyClass();
var c2 = new MyClass();

// declare 2 labels to instances on the stack
var s1 = new MyStruct();
var s2 = new MyStruct();

c1 = c2; // copies the reference data which is the pointer internally, c1 and c2 both point to the same instance
s1 = s2; // copies the data which is the struct internally, c1 and c2 both point to their own instance with the same data
Teaser t1 = new Teaser();
Teaser tPlaceHolder = t1;
t1.Foo();
public struct Foo
{
  // Fields etc here.

  public Foo(int a)
  {
    this = new Foo();
    this.a = a;
  }
}
public void SwapValues(MyStruct other)
{
  var temp = other;
  other = this;
  this = temp;
}
public struct ImmutableData
{
    private readonly int data;
    private readonly string name;

    public ImmutableData(int data, string name)
    {
        this.data = data;
        this.name = name;
    }

    public int Data { get => data; }
    public string Name { get => name; }

    public void SetName(string newName)
    {
        // this wont work
        // this.name = name; 

        // but this will
        this = new ImmutableData(this.data, newName);
    }

    public override string ToString() => $"Data={data}, Name={name}";
}

class Program
{
    static void Main(string[] args)
    {
        var X = new ImmutableData(100, "Jane");
        X.SetName("Anne");

        Debug.WriteLine(X);
        // "Data=100, Name=Anne"
    }
}
    public void ReadXml(XmlReader reader)
    {
        var data = int.Parse(reader.GetAttribute("Data"));
        var name = reader.GetAttribute("Name");

        this = new ImmutableData(data, name);
    }
    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("Data", data.ToString());
        writer.WriteAttributeString("Name", name);
    }
<?xml version="1.0" encoding="utf-8"?>
<ImmutableData Data="100" Name="Anne" />
        var xs = new XmlSerializer(typeof(ImmutableData));
        var fs = File.OpenText("Store.xml");
        var Y = (ImmutableData)xs.Deserialize(fs);
        fs.Close();