275

私は次のことをやろうとしています:

GetString(
    inputString,
    ref Client.WorkPhone)

private void GetString(string inValue, ref string outValue)
{
    if (!string.IsNullOrEmpty(inValue))
    {
        outValue = inValue;
    }
}

これにより、コンパイルエラーが発生します。私が達成しようとしていることはかなり明確だと思います。基本的に、入力文字列の内容を のプロパティGetStringにコピーしたい。WorkPhoneClient

プロパティを参照渡しすることは可能ですか?

4

14 に答える 14

496

プロパティは参照渡しできません。この制限を回避する方法をいくつか紹介します。

1.戻り値

string GetString(string input, string output)
{
    if (!string.IsNullOrEmpty(input))
    {
        return input;
    }
    return output;
}

void Main()
{
    var person = new Person();
    person.Name = GetString("test", person.Name);
    Debug.Assert(person.Name == "test");
}

2.委任

void GetString(string input, Action<string> setOutput)
{
    if (!string.IsNullOrEmpty(input))
    {
        setOutput(input);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", value => person.Name = value);
    Debug.Assert(person.Name == "test");
}

3. LINQ式

void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr)
{
    if (!string.IsNullOrEmpty(input))
    {
        var expr = (MemberExpression) outExpr.Body;
        var prop = (PropertyInfo) expr.Member;
        prop.SetValue(target, input, null);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", person, x => x.Name);
    Debug.Assert(person.Name == "test");
}

4. リフレクション

void GetString(string input, object target, string propertyName)
{
    if (!string.IsNullOrEmpty(input))
    {
        var prop = target.GetType().GetProperty(propertyName);
        prop.SetValue(target, input);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", person, nameof(Person.Name));
    Debug.Assert(person.Name == "test");
}
于 2009-09-10T01:55:33.417 に答える
34

プロパティを複製せずに

void Main()
{
    var client = new Client();
    NullSafeSet("test", s => client.Name = s);
    Debug.Assert(person.Name == "test");

    NullSafeSet("", s => client.Name = s);
    Debug.Assert(person.Name == "test");

    NullSafeSet(null, s => client.Name = s);
    Debug.Assert(person.Name == "test");
}

void NullSafeSet(string value, Action<string> setter)
{
    if (!string.IsNullOrEmpty(value))
    {
        setter(value);
    }
}
于 2012-02-01T17:13:17.660 に答える
8

プロパティの両方を取得および設定する場合は、C#7 でこれを使用できます。

GetString(
    inputString,
    (() => client.WorkPhone, x => client.WorkPhone = x))

void GetString(string inValue, (Func<string> get, Action<string> set) outValue)
{
    if (!string.IsNullOrEmpty(outValue))
    {
        outValue.set(inValue);
    }
}
于 2018-02-22T03:16:05.140 に答える
3

これは、C# 言語仕様のセクション 7.4.1 で説明されています。引数リストで ref または out パラメーターとして渡すことができるのは、変数参照のみです。プロパティは変数参照としての資格がないため、使用できません。

于 2009-09-10T00:27:23.227 に答える
3

まだ言及されていない別のトリックは、プロパティを実装するクラス (たとえばFoo、 type Bar) にデリゲートdelegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);を定義させ、メソッドActOnFoo<TX1>(ref Bar it, ActByRef<Bar,TX1> proc, ref TX1 extraParam1)(および場合によっては 2 つおよび 3 つの「追加パラメーター」のバージョンも) を実装させ、その内部表現を に渡すFooことです。提供されたプロシージャーをrefパラメーターとして。これには、プロパティを操作する他の方法よりも大きな利点がいくつかあります。

  1. プロパティは「その場で」更新されます。プロパティが「Interlocked」メソッドと互換性のある型である場合、またはそのような型の公開されたフィールドを持つ構造体である場合、「Interlocked」メソッドを使用してプロパティのアトミック更新を実行できます。
  2. プロパティが公開フィールド構造体である場合、構造体のフィールドは、冗長なコピーを作成することなく変更できます。
  3. `ActByRef` メソッドが 1 つ以上の `ref` パラメータをその呼び出し元から提供されたデリゲートに渡す場合、シングルトンまたは静的デリゲートを使用できる可能性があるため、実行時にクロージャまたはデリゲートを作成する必要がなくなります。
  4. プロパティは、いつ「操作」されているかを認識しています。ロックを保持している間は常に注意して外部コードを実行する必要がありますが、呼び出し元が別のロックを必要とする可能性のあるコールバックで何かをやりすぎないように信頼できる場合は、メソッドにプロパティへのアクセスをこれにより、「CompareExchange」と互換性のない更新が準原子的に実行される可能性があります。

物事を渡すことrefは優れたパターンです。残念ながら、それ以上使用されていません。

于 2012-12-16T21:37:13.637 に答える
2

これは不可能です。あなたは言えた

Client.WorkPhone = GetString(inputString, Client.WorkPhone);

whereWorkPhoneは書き込み可能stringなプロパティであり、 の定義GetStringは次のように変更されます

private string GetString(string input, string current) { 
    if (!string.IsNullOrEmpty(input)) {
        return input;
    }
    return current;
}

これは、あなたがしようとしているように見えるのと同じセマンティクスを持つでしょう。

プロパティは、実際には変装したメソッドのペアであるため、これは不可能です。各プロパティは、フィールドのような構文を介してアクセスできるゲッターとセッターを利用可能にします。提案したとおりに呼び出そうとするとGetString、渡されるのは変数ではなく値です。渡す値は、 getter から返されたものget_WorkPhoneです。

于 2009-09-10T00:23:02.010 に答える
2

プロパティは参照渡しできませんか? それをフィールドにして、プロパティを使用してパブリックに参照します。

public class MyClass
{
    public class MyStuff
    {
        string foo { get; set; }
    }

    private ObservableCollection<MyStuff> _collection;

    public ObservableCollection<MyStuff> Items { get { return _collection; } }

    public MyClass()
    {
        _collection = new ObservableCollection<MyStuff>();
        this.LoadMyCollectionByRef<MyStuff>(ref _collection);
    }

    public void LoadMyCollectionByRef<T>(ref ObservableCollection<T> objects_collection)
    {
        // Load refered collection
    }
}
于 2019-06-29T05:42:24.090 に答える
1

できることは、プロパティ値を保持するオブジェクトを作成することです。そうすれば、オブジェクトを渡しても、内部のプロパティにアクセスできます。

于 2010-06-02T15:58:14.200 に答える
0

その関数がコード内にあり、それを変更できる場合、受け入れられた答えは適切です。ただし、外部ライブラリのオブジェクトと関数を使用する必要があり、プロパティと関数の定義を変更できない場合があります。次に、一時変数を使用できます。

var phone = Client.WorkPhone;
GetString(input, ref phone);
Client.WorkPhone = phone;
于 2019-10-09T08:54:14.053 に答える