[解決済み] C#のボクシング・オカレンス
質問
C#でボクシングが発生するすべての状況を収集しようとしています。
-
値の型を変換して
System.Object
型に変換します。struct S { } object box = new S();
-
値の種類を変換して
System.ValueType
型に変換します。struct S { } System.ValueType box = new S();
-
列挙型の値を変換して
System.Enum
型に変換します。enum E { A } System.Enum box = E.A;
-
値型をインターフェース参照に変換する。
interface I { } struct S : I { } I box = new S();
-
C#の文字列連結で値型を使用する。
char c = F(); string s1 = "char value will box" + c;
のノートです。 の定数
char
型はコンパイル時に連結されます。のノートです。 バージョン 6.0 以降の C# コンパイラ 連結を最適化する を含む
bool
,char
,IntPtr
,UIntPtr
タイプ -
値型のインスタンスメソッドからデリゲートを作成する。
struct S { public void M() {} } Action box = new S().M;
-
値型にオーバーライドされていない仮想メソッドを呼び出す。
enum E { A } E.A.GetHashCode();
-
C# 7.0の定数パターンを使用する
is
式の下で使用します。int x = …; if (x is 42) { … } // boxes both 'x' and '42'!
-
C#のタプル型変換におけるボックス化。
(int, byte) _tuple; public (object, object) M() { return _tuple; // 2x boxing }
-
のオプションのパラメータ
object
型のデフォルト値を持つvoid M([Optional, DefaultParameterValue(42)] object o); M(); // boxing at call-site
-
の制約のない汎用型の値をチェックする。
null
:bool M<T>(T t) => t != null; string M<T>(T t) => t?.ToString(); // ?. checks for null M(42);
のノートです。 一部の.NETランタイムではJITで最適化されることがあります。
-
タイプテストの値として、制約のない、または
struct
を持つ総称型is
/as
演算子を使用します。bool M<T>(T t) => t is int; int? M<T>(T t) => t as int?; IEquatable<T> M<T>(T t) => t as IEquatable<T>; M(42);
のノートです。 一部の.NETランタイムではJITで最適化されることがあります。
箱詰めの状況は、もしかしたら隠れているかもしれませんが、他にもありますか?
どのように解決するのですか?
それは素晴らしい質問ですね。
ボクシングが発生する理由はまさに1つです。 . あなたが挙げたものはすべて、このルールに該当します。
例えばobjectは参照型なので、value型をobjectにキャストするにはvalue型への参照が必要となり、ボクシングが発生します。
すべての可能なシナリオをリストアップしたいのであれば、object または interface 型を返すメソッドから値型を返すといった派生的なものも含める必要があります。
ところで、あなたが鋭く指摘した文字列の連結のケースも、オブジェクトへのキャストから派生しています。演算子はコンパイラーによって文字列の Concat メソッドの呼び出しに変換され、渡された値の型にオブジェクトを受け入れるので、オブジェクトへのキャストとそれによる箱詰めが発生します。
長年にわたり、私は常に開発者に、ケースが長く覚えるのが大変なので、すべてのケースを記憶するのではなく、(上記で指定した)ボクシングの単一の理由を記憶するように助言してきました。これは、コンパイラが C# コードに対して生成する IL コード (たとえば、+ on string は String.Concat の呼び出しを生成する) の理解を促進することにもなります。コンパイラがどのようなコードを生成するか、また、ボックス化が発生するかどうかが不明な場合は、ILディスアセンブラ(ILDASM.exe)を使用することができます。通常、ボックス オペコードを探します(ただし、IL にボックス オペコードが含まれていないにもかかわらず、ボックス化が発生する場合があります。)
しかし、いくつかのボクシングの発生があまり明白でないことに同意します。その 1 つは、値型のオーバーライドされていないメソッドを呼び出すことです。IL コードをチェックすると、ボックス オペコードは表示されず、制約オペコードが表示されるため、IL でさえ、ボクシングが発生することは明らかではありません! この回答がさらに長くなるのを防ぐため、理由の正確な詳細には触れませんが...。
構造体から基底クラスのメソッドを呼び出す場合にも、ボクシングは発生しません。例を挙げます。
struct MyValType
{
public override string ToString()
{
return base.ToString();
}
}
ここではToStringはオーバーライドされているので、MyValTypeでToStringを呼び出してもボクシングは発生しません。しかし、実装ではベースのToStringを呼び出しているので、ボクシングが発生します(ILを確認してください!)。
ところで、これら2つの明白でない箱詰めのシナリオも、上記の1つのルールから派生しています。メソッドが値型の基底クラスで呼び出されるとき、何か この キーワードが参照するものがなければなりません。値型の基底クラスは(常に)参照型であるため、このキーワードは この キーワードは参照型を参照しなければならないので、値型への参照が必要となり、単一ルールにより箱詰めが発生します。
私のオンライン .NET コースでボクシングについて詳しく説明しているセクションへの直接のリンクは次のとおりです。 http://motti.me/mq
もしあなたがより高度なボクシングのシナリオにしか興味がないのであれば、ここに直接リンクがあります(ただし、上のリンクはより基本的なものを論じているので、そこへも行くことができます)。 http://motti.me/mu
お役に立てれば幸いです。
モッティ
関連
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み】Unity3DでOnTriggerEnterが動作しない件
-
[解決済み】なぜこのコードはInvalidOperationExceptionを投げるのですか?
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み] [Solved] .NETでスレッドの終了を待つには?
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み] なぜC#ではボクシングとアンボクシングが必要なのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み】GDI+、JPEG画像をMemoryStreamに変換する際にジェネリックエラーが発生しました。
-
[解決済み】文字列が有効な DateTime " format dd/MM/yyyy " として認識されなかった。
-
[解決済み】統合マネージドパイプラインモードで適用されないASP.NETの設定が検出された
-
[解決済み】"The ConnectionString property has not been initialized "を修正する方法
-
[解決済み】バックスラッシュを含むパス文字列のエスケープシーケンスが認識されない件
-
[解決済み】ORA-01008: すべての変数がバインドされていません。これらはバインドされています。
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する
-
[解決済み] System.Enumから整数に変換するには?