重複の可能性:
構造体がインターフェースを実装するのは安全ですか?
このコードを取る:
interface ISomeInterface
{
public int SomeProperty { get; }
}
struct SomeStruct : ISomeInterface
{
int someValue;
public int SomeProperty { get { return someValue; } }
public SomeStruct(int value)
{
someValue = value;
}
}
そして、私はこれをどこかで行います:
ISomeInterface someVariable = new SomeStruct(2);
この場合、SomeStruct
はボックス化されていますか?
はい、そうです。基本的に、参照が必要で、値型の値しかない場合は、値がボックスで囲まれています。
ここで、ISomeInterface
はインターフェイスであり、参照型です。したがって、someVariable
の値は常に参照であるため、新しく作成された構造体の値はボックス化する必要があります。
ジョンの主張は真実ですが、補足として、規則にはわずかな例外が1つあります。ジェネリック。あなたが持っている場合 where T : ISomeInterface
の場合、これはconstrainedであり、 special opcode を使用します。これは、インターフェイスを使用できることを意味しますwithoutボクシング。例えば:
public static void Foo<T>(T obj) where T : ISomeInterface {
obj.Bar(); // Bar defined on ISomeInterface
}
これは、値型T
の場合でも、notボクシングを含みます。ただし、(同じFoo
内で)次の場合:
ISomeInterface asInterface = obj;
asInterface.Bar();
その後、前と同じようにそのボックス。 constrainedonlyはT
に直接適用されます。
これを追加して、JonとMarcが提供する回答にもう少し光を当てることを願っています。
この非ジェネリックメソッドを検討してください。
public static void SetToNull(ref ISomeInterface obj) {
obj = null;
}
うーん...ref
パラメータをnullに設定しています。それはおそらく参照型の場合だけですよね? (まあ、またはNullable<T>
の場合ですが、単純にするためにその場合は無視しましょう。)したがって、このメソッドがコンパイルされるという事実は、何らかのインターフェイス型であると宣言された変数を参照型として扱う必要があることを示しています。
ここでのキーフレーズは「宣言済み」です。上記のメソッドを呼び出すこの試みを検討してください。
var x = new SomeStruct();
// This line does not compile:
// "Cannot convert from ref SomeStruct to ref ISomeInterface" --
// since x is declared to be of type SomeStruct, it cannot be passed
// to a method that wants a parameter of type ref ISomeInterface.
SetToNull(ref x);
確かに、上記のコードでx
をSetToNull
に渡すことができない理由は、x
をISomeInterface
として宣言する必要があるためです。コンパイラはSetToNull
に行ref x
が含まれていることを魔法のように知っているため、obj = null
-およびnotを渡すことができます。しかし、私の主張を補強する方法で:obj = null
行は合法です正確にはそれはillegalは、ISomeInterface
として宣言された変数notをメソッドに渡します。
言い換えると、変数がISomeInterface
として宣言されている場合は、null、純粋、および単純に設定できます。これは、インターフェイスが参照型であるためです。したがって、オブジェクトをインターフェイスとして宣言し、それを値型オブジェクトに割り当てると、その値がボックス化されます。
一方、ここで、この架空の一般的な方法を考えてみましょう。
// This method does not compile:
// "Cannot convert null to type parameter 'T' because it could be
// a non-nullable value type. Consider using 'default(T)' instead." --
// since this method could take a variable declared as, e.g., a SomeStruct,
// the compiler cannot assume a null assignment is legal.
public static void SetToNull<T>(ref T obj) where T : ISomeInterface {
obj = null;
}
MSDNドキュメント は、構造体が値であり、参照型ではないことを示しています。 object
型の変数との間で変換する場合、これらはボックスで囲まれています。しかし、ここでの中心的な質問は、インターフェイスタイプの変数はどうでしょうか。インターフェイスはクラスによっても実装できるため、Jon Skeetがすでに述べたように、これは値から参照型への変換と同等である必要があります。したがって、はいボクシングが発生します。 msdnブログでさらに議論 。