2016-01-20 11 views
5

C#で構造体とインターフェイスの間に(私によると)奇妙な違いがありました。このインタフェースや構造体を考えてみましょう:構造体とインターフェイスでのC#getters/setter

public interface INumber 
{ 
    void ChangeNumber(int n); 
    void Log(); 
} 
public struct Number : INumber 
{ 
    private int n; 
    public void ChangeNumber(int n) 
    { 
     this.n = n; 
    } 
    public void Log() 
    { 
     Console.WriteLine(this.n); 
    } 
} 

私はnを2に変更し、ログを使用して番号を印刷するのChangeNumberメソッドを使用して、プロパティとして番号を使用して新しいクラスを作成すると、それは代わりに0を出力します。

public class NumberContainer 
{ 
    public Number Number { get; set; } 
    public NumberContainer() 
    { 
     this.Number = new Number(); 
     this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 0... 
    } 
} 

this.Number.ChangeNumber(2);を呼び出すと、私は実際にゲッターのために新しいオブジェクトを作成し、その数を2に変更していたことに気付きました。しかし、その後、Numberを変更することによってコードを少し変更しましたプロパティをINumberプロパティに設定します。

public class NumberContainer 
{ 
    public INumber Number { get; set; } 
    public NumberContainer() 
    { 
     this.Number = new Number(); 
     this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 2! 
    } 
} 

この場合、2!なぜこうなった?同じ主体の構造体がインタフェースに適用されないのですか?

+1

インターフェイスとして参照されると、ボックス化されます。しかし、一般的にstructをimmuteableにするのが最善の方法です。また、muteabilityが必要な場合はクラスにする必要があります。 – juharr

答えて

4

違いはstructが値型として使用されています。interface(クラスまたは構造体で実装可能)は参照型です。

あなたの例では大きな違いがあります。最初のケースでは、this.Numberへの呼び出しは「数値の値を取得する」ことを意味します。つまり、スタックの値を取得し、スタックに格納されていない(名前のない)変数は変更されます。

もう1つのケースでは、インターフェイスは参照型です。つまり、そのアドレスに格納されているものを取得して変更します。

一般的に私は変更可能なことをお勧めしませんstruct(コメントで既に述べた通りです)。

このトピックについて詳しく読むことができます。ここで:Why are mutable structs “evil”?

2

これは、NumberContainerクラスのautoプロパティによって引き起こされます。プロパティにアクセスするときは、常に値のコピーを取得します。

プロパティをフィールドに変更すると、期待どおりに動作します。 autopropertyは単にメソッドのペアであり、その値の型は任意のメソッドに返される/渡されるときにコピーされることに注意してください。

あなたがactualy呼び出している

 this.Number.ChangeNumber(2); 
     this.Number.Log();    //prints 0... 

を呼び出している:

this.getNumber() // returns copy of value type 
     .ChangeNumber(2); // executes op on that copy 

    this.getNumber() 
     .Log(); 

あなたは操作が常に同じオブジェクトに対して実行されているので、あなたは、オブジェクトへの参照を返すされているインタフェースを使用しています。