プロパティを「out」または「ref」パラメータとして渡すことができますか?そうでない場合はどうしてですか?
例えば.
Person p = new Person();
。 。 。
public void Test(out p.Name);
短い答えをお詫びしますが、いいえ、C#言語仕様では許可されていません。
別の質問に対してこれを参照してください answer 試してみるとどうなるかを確認してください。また、制限を回避するために、プロパティを単にパブリックフィールドにするべきではない理由も示しています。
お役に立てれば
編集:なぜですか?
変数をout
またはref
パラメータに渡すと、実際には変数のアドレス(またはメモリ内の場所)が渡されます。関数内で、コンパイラは変数が実際にどこにあるかを認識し、そのアドレスに値を取得して書き込みます。
プロパティは値のように見えますが、実際には関数のペアであり、それぞれに異なるシグネチャがあります。したがって、プロパティを渡すには、実際には2つの関数ポインタを渡す必要があります。1つはget用、もう1つはset用です。
これは、変数のアドレスとはまったく異なる関数に渡すものです。
つまり、1つの変数アドレスvの2つの関数ポインタ。
更新
C#が私たちのためにこれを処理しないのはなぜですか?
私は違います Eric Lippert ですが、理由を説明します
呼び出している関数のシグネチャは何である必要がありますか?void MyFn(ref int i)
を呼び出したいとしましょう。それをそのままにしておく必要がありますか、それともプロパティも許可するように変更する必要がありますか? void MyFn(prop_ref int i)
のような構文に変更された場合、これはかなり役に立たないため、特別なprop_ref修飾子で記述されていないライブラリ関数やサードパーティのコードにプロパティを渡すことはできません。とにかく、あなたはそれが違うべきではないことを示唆していると思います。
ここで、MyFn
がi
をCOM関数またはWinAPI呼び出しに渡し、i
のアドレスを渡します(つまり、.netの外部、refによって)。プロパティの場合、どのようにしてi
のアドレスを取得しますか?プロパティの下にアドレスを取得する実際のintがない場合があります。 VB.Netが行うことをしますか?
Vb.Netコンパイラは、プロパティがByRef引数としてメソッドに渡されたときに検出します。その時点で、変数を宣言し、プロパティを変数にコピーし、変数byrefを渡し、メソッドが呼び出された後、変数をプロパティにコピーして戻します。つまり.
MyFunc(myObject.IntProperty)
になります
Dim temp_i As Integer = myObject.IntProperty
MyFunc(temp_i)
myObject.IntProperty = temp_i
プロパティの副作用はMyFunc
が返されるまで発生しません。これにより、あらゆる種類の問題が発生し、非常に微妙なバグが発生する可能性があります。
私の謙虚な意見では、この問題に対するVb.Netソリューションも壊れているので、それを答えとして受け入れるつもりはありません。
C#コンパイラはこれをどのように処理する必要があると思いますか?
他の人は、C#ではこれを行うことができないと説明しています。 VB.NETでは、オプションstrict/explicitがオンの場合でもcanこれを実行します。
Option Strict On
Option Explicit On
Imports System.Text
Module Test
Sub Main()
Dim sb as new StringBuilder
Foo (sb.Length)
End Sub
Sub Foo(ByRef x as Integer)
End Sub
End Module
上記のコードは、このC#コードと同等です。
using System.Text;
class Test
{
static void Main()
{
StringBuilder sb = new StringBuilder();
int tmp = sb.Length;
Foo(ref tmp);
sb.Length = tmp;
}
static void Foo(ref int x)
{
}
}
個人的には、C#にこれがないことを嬉しく思います。特に、パラメーターがメソッド内に設定されている場合にプロパティの値に関して、例外がスローされると、水がかなり濁っています。
編集:要求されたように、私がなぜ泥の中の財産を渡すと信じているのかについての私の推論は水を濁します。参照によって正規変数を渡すと、その変数はメソッド内で参照されるたびに評価されます。何らかの理由で値が変更された場合(たとえば、メソッド内の他の作業の副作用として)、その変更はメソッドにすぐに表示されます。 VB.NETで参照によってプロパティを渡す場合は、そうではありません。プロパティゲッターが1回呼び出され、次にプロパティセッターが1回呼び出されます。 「パラメータを使用するたびに、そこから取得して設定するプロパティ-」を渡すのとは異なります。
これは、.NETでフィールドを渡すこととまったく些細なプロパティを渡すことで結果が大きく異なる完全な例です。
Option Strict On
Option Explicit On
Imports System.Text
Class Test
Dim counter as Integer
Property CounterProperty As Integer
Get
Return counter
End Get
Set (ByVal value as Integer)
counter = value
End Set
End Property
Sub Increment
counter += 1
End Sub
Shared Sub Main()
Dim t as new Test()
Console.WriteLine("Counter = {0}", t.counter)
t.Foo(t.counter)
Console.WriteLine("Counter = {0}", t.counter)
t.CounterProperty = 0
Console.WriteLine("CounterProperty = {0}", t.CounterProperty)
t.Foo(t.CounterProperty)
Console.WriteLine("CounterProperty = {0}", t.CounterProperty)
End Sub
Sub Foo(ByRef x as Integer)
x = 5
Increment
Increment
Increment
x += 1
End Sub
End Class
これが許可されないもう1つの理由は、refおよびoutパラメーターがメソッド内で読み取りおよび書き込み可能であるのに対し、プロパティは読み取り専用/書き込み専用である可能性があるためです。
Person
{
public string Name { get { return "me"; } }
}
さて、これができるとしたらどうでしょうか?
Test(out p.Name);
public void Test(out string name)
{
name = "someone else";
}
あなたは今あなたではなく他の誰かですが、それはあなたがget
のみのプロパティName
と結んだ契約に反しています(これがうまくいったとしても)。これは、クラスの読み取り専用メンバーフィールドの場合と同じであり、それらの参照を渡すことはできません。
Person
{
public readonly string name = "me";
}
Test(out p.name); //not possible.
多分 C#
は、メソッドの読み取り専用/書き込み専用引数を考え出すことができます。
public void Test(out settable string name, gettable int count, bool whatever)
{
name = "someone else";
}
Test(out p.Name, 0, true); // doesnt compile since p.Name is readonly.
代わりに、このようなことをする必要があります
WhatEverTheType name;
Test(out name);
// Choose one of the following construction
Person p = new Person();
p.Name = name;
Person p = new Person(name);
Person p = new Person(Name => name);