我在使用一类结构时遇到了问题。
这是基本定义:
using System;
struct Real
{
public double real;
public Real(double real)
{
this.real = real;
}
}
class Record
{
public Real r;
public Record(double r)
{
this.r = new Real(r);
}
public void Test(double origval, double newval)
{
if (this.r.real == newval)
Console.WriteLine("r = newval-test passed\n");
else if (this.r.real == origval)
Console.WriteLine("r = origval-test failed\n");
else
Console.WriteLine("r = neither-test failed\n");
}
}
当我创建一个非动态(静态?)记录时,设置Real工作 当我创建动态记录时,设置真实不起作用 当我创建一个动态记录,取代真实的作品。
这是测试程序
class Program
{
static void Main(string[] args)
{
double origval = 8.0;
double newval = 5.0;
// THIS WORKS - create fixed type Record, print, change value, print
Record record1 = new Record(origval);
record1.r.real = newval; // change value ***
record1.Test(origval, newval);
// THIS DOESN'T WORK. change value is not making any change!
dynamic dynrecord2 = new Record(origval);
dynrecord2.r.real = newval; // change value
dynrecord2.Test(origval, newval);
// THIS WORKS - create dynamic type Record, print, change value, print
dynamic dynrecord3 = new Record(origval);
dynamic r = dynrecord3.r; // copy out value
r.real = newval; // change copy
dynrecord3.r = r; // copy in modified value
dynrecord3.Test(origval, newval);
}
}
这是输出: r = newval-test通过 r = origval-test失败 r = newval-test传递
当我将struct Real更改为Real类时,所有三种情况都有效。
那是怎么回事?
谢谢,
最大
答案 0 :(得分:1)
dynamic
对于object
来说确实是一个奇特的词,因此您正在改变一个盒装副本。这很容易发疯。首先突变结构 确实非常容易出错。我只是简单地使结构不可变 - 否则你将一遍又一遍地得到 。
答案 1 :(得分:0)
我深入研究了这个问题。以下是微软Mads Torgersen的回答。
来自Mads:
这有点不幸但是设计不合适。在
dynrecord2.r.real = newval; // change value
dynrecord2.r的值被装箱,这意味着复制到它自己的堆对象中。该副本是经过修改的副本,而不是您随后测试的副本。
这是C#动态工作的非常“本地”方式的结果。想想上面的陈述 - 我们可以通过两种基本方式来攻击它:
1)在编译时实现动态正在发生的事情,并且基本上将整个语句移动到运行时绑定
2)当它们的成分是动态的时,在运行时绑定各个操作,返回动态的东西,这可能反过来导致事物在运行时绑定
在C#中,我们使用了后者,这非常合成,并且可以很容易地根据类型系统来描述动态,但是有一些缺点 - 例如拳击结果值类型。
所以你所看到的是这种设计选择的结果。
我又看了一眼MSIL。它基本上需要
dynrecord2.r.real = newval;
并将其变为:
Real temp = dynrecord2.r;
temp.real = newval;
如果dynrecord2.r是一个类,它只是复制句柄,因此更改会影响内部字段。如果dynrecord2.r是结构,则会生成副本,并且更改不会影响原始结构。
我将由读者决定这是一个错误还是一个功能。
最高
答案 2 :(得分:0)
让你的结构不可变,你就不会有问题。
struct Real
{
private double real;
public double Real{get{return real;}}
public Real(double real)
{
this.real = real;
}
}
可变结构在本机互操作或某些高性能场景中非常有用,但是您可以更好地了解自己在做什么。