5

それは私が信じている非常に単純な質問です。このコードが1050ではなく1000を出力する理由を誰か説明できますか

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;
        }
    }
}
4

3 に答える 3

8

struct値の型 ( ) をインターフェイス ボックスにキャストすると、値が格納されます。したがって、値自体ではなく、ボックス化された値のコピーに対してメソッドを呼び出しています。

于 2013-02-14T15:53:23.357 に答える
1

値型 ( ) はvalue によってstruct渡されますが、インターフェイスは (値型ではなく)参照型と見なされます。どれどれ:

Bus b = new Bus(1000);

ボリュームが 1000 に設定された aのbが含まれるようになりました。Bus

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());

それでおしまい。

于 2013-02-14T16:03:14.867 に答える
0

値型が変化するインターフェイスを実装すると便利な場合もありますが、そのような型は細心の注意を払って使用する必要があります。C# がすべての値型をオブジェクトであると見なすという事実は、その点で少し役に立ちません (実際には、それらは に変換できるものですObject)。これは、コンパイラに誤った使用法について警告させる方法がないことを意味するためです。

インターフェースを完全に無視するオプションは別として、変更インターフェース型を使用するコードは、次の 2 つのいずれかを実行する必要があります。

  1. 構造体のインスタンスをインターフェイス タイプにキャストし、インターフェイス タイプ、Object、または ValueType 以外にキャストしないでください。特に、それ自体の型にキャストし直さないでください。インスタンスが独自の型にキャストバックされない限り、異なるインターフェイスまたは参照型間のキャストは問題ないことに注意してください。これは List.Enumerator のようなもので最も一般的なパターンで、しばしば IEnumerator にキャストされ、それ以外には決してキャストされません。
  2. struct をインターフェイス型として使用しないでください。ただし、それを変更することになっているメソッドに、制約付きのジェネリック ref パラメータとして渡す場合を除きます。これを行うコードは、多くの場合、構文的には「不格好」ですが、意味的には正しいものになります。構造体代入を使用して構造体シェイプのスナップショットを取得できるという事実により、他の手段では容易にまたは効率的に利用できないセマンティクスが可能になる可能性がありますが、コンパイラの診断を引き起こさないが結果をもたらさないミスを犯す多くの方法があります正しい動作。

ほとんどの場合、変化するインターフェイスを実装するために何かが必要な場合、問題の型はクラスである必要があります。可変構造体は、一般に、基になるフィールドを直接変更するか、または によって渡されたインスタンスで動作する静的メソッドを使用することによってのみ、変更を許可する必要がありますref

于 2013-02-18T23:08:52.840 に答える