(见下面我用我接受的答案创建的解决方案)

我试图提高一些涉及反射的代码的可维护性。该应用程序有一个。net Remoting接口,其中包括一个名为Execute的方法,用于访问应用程序中未包含在其发布的远程接口中的部分。

下面是应用程序如何指定属性(本例中的静态属性),这意味着可以通过Execute访问:

RemoteMgr.ExposeProperty("SomeSecret", typeof(SomeClass), "SomeProperty");

因此远程用户可以调用:

string response = remoteObject.Execute("SomeSecret");

应用程序将使用反射来查找SomeClass。SomeProperty并以字符串形式返回它的值。

不幸的是,如果有人重命名SomeProperty并且忘记更改ExposeProperty()的第3个参数,就会破坏这个机制。

我需要的是:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

作为ExposeProperty中的第三个parm,这样重构工具就会照顾到重命名。

有办法做到这一点吗?

好吧,这是我最终创建的(基于我选择的答案和他引用的问题):

// <summary>
// Get the name of a static or instance property from a property access lambda.
// </summary>
// <typeparam name="T">Type of the property</typeparam>
// <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
// <returns>The name of the property</returns>
public string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    var me = propertyLambda.Body as MemberExpression;

    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    return me.Member.Name;
 }

用法:

// Static Property
string name = GetPropertyName(() => SomeClass.SomeProperty);

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);

现在有了这个很酷的功能,是时候简化ExposeProperty方法了。擦门把手是危险的工作。


当前回答

在c# 6.0中,这不是问题,因为你可以这样做:

nameof(SomeProperty)

这个表达式在编译时被解析为“SomeProperty”。

名称的MSDN文档。

其他回答

我在使用已经为我的特定用例建议的解决方案时遇到了一些困难,但最终解决了这个问题。我不认为我的具体情况值得一个新的问题,所以我在这里张贴我的解决方案供参考。(这与问题密切相关,并为其他与我有类似情况的人提供了解决方案)。

我最终得到的代码是这样的:

public class HideableControl<T>: Control where T: class
{
    private string _propertyName;
    private PropertyInfo _propertyInfo;

    public string PropertyName
    {
        get { return _propertyName; }
        set
        {
            _propertyName = value;
            _propertyInfo = typeof(T).GetProperty(value);
        }
    }

    protected override bool GetIsVisible(IRenderContext context)
    {
        if (_propertyInfo == null)
            return false;

        var model = context.Get<T>();

        if (model == null)
            return false;

        return (bool)_propertyInfo.GetValue(model, null);
    }

    protected void SetIsVisibleProperty(Expression<Func<T, bool>> propertyLambda)
    {
        var expression = propertyLambda.Body as MemberExpression;
        if (expression == null)
            throw new ArgumentException("You must pass a lambda of the form: 'vm => vm.Property'");

        PropertyName = expression.Member.Name;
    }
}

public interface ICompanyViewModel
{
    string CompanyName { get; }
    bool IsVisible { get; }
}

public class CompanyControl: HideableControl<ICompanyViewModel>
{
    public CompanyControl()
    {
        SetIsVisibleProperty(vm => vm.IsVisible);
    }
}

对我来说重要的部分是,在CompanyControl类编译器只允许我选择一个布尔属性的ICompanyViewModel,这使得其他开发人员更容易得到它的权利。

我的解决方案与公认答案之间的主要区别是,我的类是泛型的,我只想匹配泛型类型中的布尔型属性。

老问题了,但是这个问题的另一个答案是在使用CallerMemberNameAttribute的helper类中创建一个静态函数。

public static string GetPropertyName([CallerMemberName] String propertyName = null) {
  return propertyName;
}

然后像这样使用它:

public string MyProperty {
  get { Console.WriteLine("{0} was called", GetPropertyName()); return _myProperty; }
}

我修改了您的解决方案,以链接多个属性:

public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    MemberExpression me = propertyLambda.Body as MemberExpression;
    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    string result = string.Empty;
    do
    {
        result = me.Member.Name + "." + result;
        me = me.Expression as MemberExpression;
    } while (me != null);

    result = result.Remove(result.Length - 1); // remove the trailing "."
    return result;
}

用法:

string name = GetPropertyName(() => someObject.SomeProperty.SomeOtherProperty);
// returns "SomeProperty.SomeOtherProperty"

在c# 6.0中,这不是问题,因为你可以这样做:

nameof(SomeProperty)

这个表达式在编译时被解析为“SomeProperty”。

名称的MSDN文档。

这就是我实现它的方式,背后的原因是如果你想从它的成员中获取名称的类不是静态的,那么你需要创建它的一个实例,然后获取成员的名称。所以这里的一般性就有用了

public static string GetName<TClass>(Expression<Func<TClass, object>> exp)
{
    MemberExpression body = exp.Body as MemberExpression;

    if (body == null)
    {
         UnaryExpression ubody = (UnaryExpression)exp.Body;
         body = ubody.Operand as MemberExpression;
    }

     return body.Member.Name;
}

用法是这样的

var label = ClassExtension.GetName<SomeClass>(x => x.Label); //x is refering to 'SomeClass'