C# 为什么结构中的这个值根本没有改变?
我相信这是一个非常简单的问题。有人能解释为什么这个代码输出1000而不是1050吗C# 为什么结构中的这个值根本没有改变?,c#,interface,C#,Interface,我相信这是一个非常简单的问题。有人能解释为什么这个代码输出1000而不是1050吗 public class Program { public static void Main() { Bus b = new Bus(1000); ((Car)b).IncreaseVolume(50); Console.WriteLine(b.GetVolume()); } }
public class Program
{
public static void Main()
{
Bus b = new Bus(1000);
((Car)b).IncreaseVolume(50);
Console.WriteLine(b.GetVolume());
}
}
public interface Car
{
int GetVolume();
void IncreaseVolume(int amount);
}
public struct Bus : Car
{
private int volume;
public Bus(int volume)
{
this.volume = volume;
}
public int GetVolume()
{
return volume;
}
public void IncreaseVolume(int amount)
{
volume += amount;
}
}
}
将值类型(struct
)强制转换为接口会将该值框起来。因此,您是在值的盒装副本上调用方法,而不是在值本身上调用方法。值类型(struct
)是按值传递的,但接口被视为引用类型(而不是值类型)。让我们看看:
Bus b = new Bus(1000);
现在b
包含一个Bus
的值,其音量设置为1000
Car c = (Car)b;
现在,b
中的值被复制并制成Car
的参考类型(已装箱)。现在c
包含一个指向装箱副本的指针
c.IncreaseVolume(50);
在参考类型上,您调用IncreaseVolume
,它是Car
界面的成员。它接收对装箱值的引用。它接受指向框中值的托管指针(使其再次成为值类型)
现在,您的方法将作用于框中的值:
public void IncreaseVolume(int amount)
{
volume += amount;
}
现在该方法返回。请注意,在b
中,没有任何操作对值起作用,只对其副本起作用。因此,下一条语句将打印1000
:
Console.WriteLine(b.GetVolume());
就是这样。尽管有时值类型实现变异接口很有用,但使用此类类型时必须格外小心。事实上,C#假装所有值类型都是对象在这方面是没有帮助的(实际上,它们是可转换为
对象
),因为这意味着编译器无法警告错误的使用
除了完全忽略接口的选项外,通常有必要使用变异接口类型的代码必须执行以下两项操作之一:
在大多数情况下,如果需要一些东西来实现一个变异接口,那么所讨论的类型应该是一个类。可变结构通常只允许通过直接修改基础字段或使用对
ref
传递的实例进行操作的静态方法进行变异,因为Bus
是结构。把它变成一个类
。正如你的问题标题所暗示的那样,你不是在把类
转换成一个接口,而是一个结构
。谢谢你,我以为我是在处理类。愚蠢的错误,可能会被关闭。甚至不需要强制转换,因为Bus
(作为类,而不是结构)必须实现该方法,所以调用((Car)b)。IncreaseVolume(50)
与b.IncreaseVolume(50)
完全相同,提供的总线是一个类。@JohnWillemse:我想OP知道这一点,这是一个简化的例子。考虑一个方法,它使用汽车
并在内部调用递增音量
,然后在使用总线
调用该方法后,您调用GetVolume
,值没有改变,您想知道为什么。使用对象可以很容易地显示这一点。ReferenceEquals
:object.ReferenceEquals(b,(Car)b)
将为false
@DanielHilgarth:这表明,当您将一个值装箱两次时,它每次都会创建一个新对象。实际上没有办法检查值和引用是否相同。根据定义,它们已经不是了。“框两次”,因为ReferenceEquals
的参数属于object
类型,并且传递值类型将已经将其框起来?@DanielHilgarth:是的,没错。我很确定对包含结构的变量调用方法之间没有区别,包含结构的对象或包含结构的数组元素。无需先复制该值。您是指额外变量Car c
?这只是为了解释。我的意思是“它通过复制装箱对象中的值来解除对该值的装箱(使其再次成为值类型)。”我认为不会发生这种情况。它怎么可能不会发生呢?毕竟,IncreaseVolume
是一个值类型的实例方法,因此它的this
应该是一个值类型。传递给接口方法的this
是引用类型,因此需要取消绑定。值在框内。该方法可以在此基础上操作,不需要首先提取值。与数组元素中的结构值进行比较<代码>var a=新车[1];a[0]=新车(1000辆);a[0]。增加体积(50);var result=a[0]。GetVolume();//结果==1050
Console.WriteLine(b.GetVolume());