我想做的是:

GetString(
    inputString,
    ref Client.WorkPhone)

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

这给了我一个编译错误。我想我想达到的目的已经很清楚了。基本上我想要GetString复制输入字符串的内容到客户端的WorkPhone属性。

是否可以通过引用传递属性?


当前回答

您可以尝试做的是创建一个对象来保存属性值。这样,您可以传递对象,但仍然可以访问内部的属性。

其他回答

受Sven的表达式树解决方案的启发,下面是一个不依赖反射的简化版本。此外,它还删除了不必要的自定义getter和字段表达式。

using System;
using System.Linq.Expressions;

namespace Utils;

public class Accessor<T>
{
    public Accessor(Expression<Func<T>> expression)
    {
        if (expression.Body is not MemberExpression memberExpression)
            throw new ArgumentException("expression must return a field or property");
        var parameterExpression = Expression.Parameter(typeof(T));

        _setter = Expression.Lambda<Action<T>>(Expression.Assign(memberExpression, parameterExpression), parameterExpression).Compile();
        _getter = expression.Compile();
    }

    public void Set(T value) => _setter(value);
    public T Get() => _getter();

    private readonly Action<T> _setter;
    private readonly Func<T> _getter;
}

只是对内森的Linq表达式解决方案的一点扩展。使用多泛型参数,使属性不限于字符串。

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

为了对这个问题进行投票,这里有一个关于如何将其添加到语言中的积极建议。我并不是说这是最好的方法,请随意提出你自己的建议。但是允许像Visual Basic那样通过ref传递属性将极大地帮助简化一些代码,而且经常如此!

https://github.com/dotnet/csharplang/issues/1235

这是不可能的。你可以说

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

其中WorkPhone是一个可写的字符串属性和GetString的定义被更改为

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

这将具有与您所尝试的相同的语义。

这是不可能的,因为属性实际上是一对伪装的方法。每个属性都提供了可通过类字段语法访问的getter和setter。当您尝试调用GetString时,您传递的是一个值而不是一个变量。您传入的值是从getter get_WorkPhone返回的。

你不能引用一个属性,但如果你的函数同时需要get和set访问,你可以传递一个定义了属性的类实例:

public class Property<T>
{
    public delegate T Get();
    public delegate void Set(T value);
    private Get get;
    private Set set;
    public T Value {
        get {
            return get();
        }
        set {
            set(value);
        }
    }
    public Property(Get get, Set set) {
        this.get = get;
        this.set = set;
    }
}

例子:

class Client
{
    private string workPhone; // this could still be a public property if desired
    public readonly Property<string> WorkPhone; // this could be created outside Client if using a regular public property
    public int AreaCode { get; set; }
    public Client() {
        WorkPhone = new Property<string>(
            delegate () { return workPhone; },
            delegate (string value) { workPhone = value; });
    }
}
class Usage
{
    public void PrependAreaCode(Property<string> phone, int areaCode) {
        phone.Value = areaCode.ToString() + "-" + phone.Value;
    }
    public void PrepareClientInfo(Client client) {
        PrependAreaCode(client.WorkPhone, client.AreaCode);
    }
}