为什么结构中的这个值根本没有变化?

时间:2013-02-14 15:50:27

标签: 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 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;
        }
    }
}

3 个答案:

答案 0 :(得分:8)

将值类型(struct)转换为接口框的值。所以你要在值的盒装副本上调用方法,而不是在值本身上调用。

答案 1 :(得分:1)

值类型(struct)按值传递,但接口被视为引用类型(不是值类型)。我们来看看:

Bus b = new Bus(1000);

现在b包含Bus,其音量设置为1000.

Car c = (Car)b;

现在b中的值被复制并成为Car的引用类型(盒装)。现在c包含指向盒装副本的指针。

c.IncreaseVolume(50);

在引用类型上,您调用IncreaseVolume,它是Car接口的成员。它接收对盒装值的引用。它需要一个指向框中值的托管指针(使其再次成为值类型)。

void Car.IncreaseVolume(int amount)
{
    ((Bus)this).IncreaseVolume(amount);
}

现在,您的方法将对框中的值执行操作:

public void IncreaseVolume(int amount)
{
    volume += amount;
}

现在该方法返回。请注意,b中的值只对其副本执行了操作。所以下一个语句将打印1000

Console.WriteLine(b.GetVolume());

就是这样。

答案 2 :(得分:0)

虽然有时值类型可以用来实现变异接口,但必须非常谨慎地使用这些类型。 C#假装所有值类型都是对象的事实在这方面有点无益(实际上,它们是 convertible Object的东西),因为它意味着没有办法使编译器警告不正确的用法。

除了完全忽略接口的选项之外,通常需要使用变异接口类型的代码必须执行以下两种操作之一:

  1. 将结构的实例强制转换为接口类型,并且永远不会再将它强制转换为接口类型,`Object`或`ValueType`以外的任何其他类型。特别是,永远不要把它归还给自己的类型。请注意,如果实例永远不会强制转换为自己的类型,则可以在不同的接口或引用类型之间进行转换。这是最常见的模式,例如`List.Enumerator`,它经常被强制转换为`IEnumerator`而从不投射到任何其他东西。
  2. 永远不要使用struct作为接口类型,除非将它作为约束通用`ref`参数传递给任何应该修改它的方法。执行此操作的代码通常在语法上“笨拙”,但在语义上是正确的。结构赋值可用于获取结构形状的快照这一事实可能允许通过其他方式不容易或有效地获得的语义,但有许多方法可以犯错误,这些错误不会导致编译器诊断但不会产生正确的行为。

在大多数情况下,如果需要某些东西来实现变异的接口,那么所讨论的类型应该是一个类。可变结构通常只允许通过直接修改底层字段或使用对ref传递的实例进行操作的静态方法来实现突变。