単純な = を使用した参照質問によって異なります
-
06-07-2019 - |
質問
by refの質問にはバリエーションがあります。私は、ref またはパラメーターを使用した呼び出しについて、またそれが変数とその値にどのように影響するかをすべて知っています。DataTable でこの問題が発生しました。データテーブルが単純な整数変数と異なる理由を知りたいと思っています。
問題を解決する方法について物理的な答えはありますが、なぜそのように機能するのかを知りたいです。
単純な変数を使用すると、期待どおりの結果が得られます
int mVar1 = 1;
int mVar2 =1;
mVar2 = mVar1;
mVar2 = 5;
Console.WriteLine(mVar1.ToString());
Console.WriteLine(mVar2.ToString());
コンソールに1,5が表示されます。
ただし、DataTable で同じことを行うと、新しい値の代わりに最初のデータテーブルへの参照が作成されます。
DataTable mVar3 = new DataTable();
DataTable mVar4 = new DataTable();
// Create DataColumn objects of data types.
DataColumn colString = new DataColumn("StringCol");
colString.DataType = System.Type.GetType("System.String");
mVar3.Columns.Add(colString);
// Create DataColumn objects of data types.
DataColumn colString2 = new DataColumn("StringCol123");
colString2.DataType = System.Type.GetType("System.String");
mVar4.Columns.Add(colString2);
foreach (DataColumn tCol in mVar3.Columns)
{
Console.WriteLine(tCol.ColumnName);
}
foreach (DataColumn tCol in mVar4.Columns)
{
Console.WriteLine(tCol.ColumnName);
}
mVar4 = mVar3;
//change mVar4 somehow and see if mVar3 changes
foreach (DataColumn tCol in mVar4.Columns)
{
tCol.ColumnName = "Test";
}
foreach (DataColumn tCol in mVar3.Columns)
{
Console.WriteLine(tCol.ColumnName);
}
foreach (DataColumn tCol in mVar4.Columns)
{
Console.WriteLine(tCol.ColumnName);
}
コンソールには以下が表示されます。文字列コル 文字列Col123 テスト テスト
mVar4 = mVar3 とすると、mVar4 が mVar3 への参照になります。
この問題の解決策はこう言うことです
DataTable mVar4 = mVar3.Copy();
そこで私の質問は次のとおりです。データテーブルの動作が単純な整数フィールドと異なる原因は何ですか。DataTable の別のコピーではなく mVar4 = mVar3 を使用すると参照が作成されるのはなぜですか?
解決
参照型と値型の違いに直面しています。
ここにあります msdnの記事 違いについて。
より説明的な答えは、両方が実際には同じ演算を実行しているということです。違いは、最初の例 (2 つの整数) では、mVar2 = mVar1 の割り当てが mVar1 の値 (1) を mVar2 に割り当てていることです。ただし、DataTable の場合、実際に割り当てられるのは DataTable ではなくメモリの場所です。
たとえば、作成した DataTable がメモリ位置 20 にあるとします。これは、参照 mVar1 がその場所 (20) への参照を保持することを意味します。mVar2 = mVar1 を代入すると、mVar2 に mVar1 と同じ値を保持するように指示することになり、mVar2 はメモリ位置 20 も参照します。その結果、両方の変数が同じ DataTable を参照します。
あなたが説明している動作を実現するには、あなたが述べたように、確かにコピー能力が必要です。まったく新しいオブジェクトを割り当て、前のオブジェクトの状態を新しいオブジェクトにコピーする必要があります。
DataTable クラスの場合、拡張メソッド内で次のように拡張できます。
public static DataTable Copy(this DatTable original)
{
var result = new DataTable();
//assume Property1 was a property of a DataTable
result.Property1 = original.Property1;
//continue copying state from original to result
return result;
}
他のヒント
呼び出しmVar2 = mVar1; mVar1の場所に保存されている値をコピーします。このシナリオでは、1はmVar2の場所にコピーされます。 2番目の状況では、mVar3に保存された値がmVar4の場所に再びコピーされます。ただし、この場合、DataTableは参照型であるため、コピーされる値は実際のDataTableオブジェクトへの参照です。
これをさらに表示するには、投稿したコードの最後に次を追加します。
mVar4 = new DataTable();
// Create DataColumn objects of data types.
DataColumn colString3 = new DataColumn("StringCol1234");
colString2.DataType = System.Type.GetType("System.String");
mVar4.Columns.Add(colString3);
foreach (DataColumn tCol in mVar3.Columns)
{
Console.WriteLine(tCol.ColumnName); // still outputs test
}
foreach (DataColumn tCol in mVar4.Columns)
{
Console.WriteLine(tCol.ColumnName); // now outputs StringCol1234
}
ここで、再びmVar4をDataTableの新しいインスタンスに設定すると、行われた変更はmVar3に反映されません。これは、呼び出しmVar4 = new DataTable(); mVar4の位置で参照を変更しますが、mVar4が参照するオブジェクトは変更しません。