リンクできる変数の型は? 私はオブジェクトを使用しようとしましたが、それは私が望むことをしませんでした.
object a;
object b;
b = 5;
a = b;
b = 2;
label1.Text = Convert.ToString(a);
5と書いてあるけど2にしたい。
これは、参照とそれらがどのように機能するか、変数とは何かについての単純な誤解です。
object a; // a is a storage location
// it holds references to instances of object
object b; // b is a storage location
//it holds references to instances of object
b = 5; // "boxes" 5 into an instance of object
// and assigns reference to that object to b
a = b; // assigns reference in storage location b to storage location a
b = 2; // "boxes" 2 into an instance of object
// and assign reference to that object to b
このように考えてください。a
家b
の住所が書かれた紙切れです。というときは、家の住所を紙にb = 5
書き留めているようなものだと考えてください。というときは、 に書かれている住所をコピーするようなものだと思ってください。と言う時は、書いてある住所を消して、自宅の住所に置き換えると考えてください。このアクションは、紙に書かれている値を変更しません。それがここで起こっていることです。5
b
a = b
b
a
b = 2
b
2
a
では、やろうとしていることを機能させるための非常に簡単な方法を見てみましょう。
class MyValue {
public int Value { get; set; }
}
MyValue b = new MyValue { Value = 5 };
MyValue a = b;
b.Value = 2;
今、あなたが言うなら
Console.WriteLine(a.Value);
何が起こるか?慎重に推論しましょう。再び、住所が書かれた紙片としてのa
とのアナロジーに戻ります。b
私たちは言っMyValue b = new MyValue { Value = 5 }
た。b
これは、家の住所を紙に書き留め5
、玄関ドアの上に書いてあると考えてください。に書かれている住所をコピーするa = b
ようなものだと思ってください。次に、正面玄関の上の標識の値を変更すると考えてください。この場合は、 を に変更します。さて、誰かが尋ねたら、紙に書かれた住所のある家のドアの上にある値は何ですか? 上のアドレスは上のアドレスと同じですb
a
b.Value = 2
5
2
a
a
b
. 正面玄関の上の標識の値を から に変更しまし5
た2
。だから、私たちは見ることを期待しています2
。
試してみてください2
。コンソールに出力された値が表示されます。
骨の奥深くまで感じるまで、これについて何度も何度も考えてください。この基本的な概念を理解するまでは、プログラミングについての推論は非常に困難であることがわかります。
ジェイソンの答えは良いです。さらに追加するには:
これは同じ変数のエイリアスであることa = b
を意味するa
と言うと、それを期待しているようです。それは意味するものではありません。とは、保管場所の内容を保管場所にコピーすることを意味し、保管場所のラベルを付け直すことではありません。b
a = b
b
a
a
ただし、2 つの変数を互いにエイリアスにする方法があります。実際、C# でこれを行うには3 つの方法があります (Jason が提案する手法に加えて、おそらくこれが最適です)。
最初の方法はref
、out
パラメーターを使用することです。
class P
{
static object b = 5;
static void M(ref object a)
{
b = 2;
Console.WriteLine(a);
}
static void Main()
{
M(ref b);
}
}
これを実行すると、希望どおりに動作することがわかります。b
として始まり5
、次にとがエイリアスになるref
ことを意味します。が に変更された場合も、2 つの異なる名前を持つ同じ変数であるためです。a
b
b
2
a
ただし、単一のメソッド内でこれを行う方法はありません。基礎となるランタイムはこれをサポートしており、私は以前、サポートされている C# のバージョンを作成しました。
object b = 5;
ref object a = ref b;
b = 2;
// now a is 2
しかし、これが顧客に出荷される言語のバージョンになることはありませんでした。
ある変数を別のエイリアスにする 2 つ目の方法は、上級プログラマ向けです。逆参照されたときに変数をエイリアスするポインターを作成できます。
int b = 5;
int* a = &b;
b = 2;
// Now *a is 2
ポインター型は、 のような管理された型int
ではなく、のような「管理されていない型」の変数のみをエイリアスできることに注意してください。object
私は高度な C# を 10 年間プログラミングしてきましたが、これを製品コードで行う必要があったことは一度もありません。
1 つの変数エイリアスを別の変数にする 3 番目の方法は、上級プログラマ専用です。C#の型といくつかの文書化されていない機能を使用しTypedReference
て、変数への参照をキャプチャし、後でエイリアスに逆参照することができます。私のアドバイスは、この機能を使用しないことです。
using System;
class Program
{
static void Main(string[] args)
{
ValueTypeWrapper<int> a;
ValueTypeWrapper<int> b;
// The following line creates a new instance
// of ValueTypeWrapper<int> by the means of
// implicit conversion (see last method defined
// in the ValueTypeWrapper<T> class).
b = 5;
// Make the variable "a" point to the same
// ValueTypeWrapper<int> instance we just created.
a = b;
// Now that both variables are pointing to
// the same *instance*, change the value of
// the Value property.
b.Value = 2;
// Convert.ToString(...) will call
// ValueTypeWrapper<int>'s ToString()
// method, which in turn produces the
// string equivalent of the value inside
// the Value property.
// The Value property is equal to 2
// on both "a" and "b" objects as they
// point to the same instance.
Console.WriteLine(Convert.ToString(a));
Console.ReadLine();
}
}
public class ValueTypeWrapper<T> where T : struct
{
public T Value { get; set; }
public override string ToString()
{
return this.Value.ToString();
}
public static implicit operator ValueTypeWrapper<T>(T value)
{
return new ValueTypeWrapper<T> { Value = value };
}
}