获取属性的名称作为字符串

Jim*_*m C 191 c# reflection properties

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

我正在尝试提高一些涉及反射的代码的可维护性.该应用程序有一个.NET Remoting接口,公开(除此之外)一个名为Execute的方法,用于访问未包含在其已发布的远程接口中的应用程序部分.

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

RemoteMgr.ExposeProperty("SomeSecret", typeof(SomeClass), "SomeProperty");
Run Code Online (Sandbox Code Playgroud)

所以远程用户可以调用:

string response = remoteObject.Execute("SomeSecret");
Run Code Online (Sandbox Code Playgroud)

并且应用程序将使用反射来查找SomeClass.SomeProperty并将其值作为字符串返回.

不幸的是,如果有人重命名SomeProperty并忘记更改ExposeProperty()的第3个parm,它会破坏这种机制.

我需要相当于:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()
Run Code Online (Sandbox Code Playgroud)

在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;
 }
Run Code Online (Sandbox Code Playgroud)

用法:

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

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);
Run Code Online (Sandbox Code Playgroud)

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

感谢大家.

Jam*_* Ko 410

使用C#6.0,现在这可以解决问题:

nameof(SomeProperty)
Run Code Online (Sandbox Code Playgroud)

此表达式在编译时解析为"SomeProperty".

MSDN文档名称.

  • 这是badass,对ModelState.AddModelError调用非常有用. (17认同)
  • 这是一个`const string`!惊人 (8认同)
  • @RaidenCore当然,如果你正在编写一个微控制器,你应该使用像C这样的低级语言,如果你需要挤压像图像和视频处理这样的各种性能,你应该使用C或C++.但对于其他95%的应用程序,托管代码框架将足够快.最终C#也被编译为机器代码,如果需要,您甚至可以将其预编译为本机代码. (4认同)
  • 只要您不应用混淆,nameof 就很酷,如果您的属性名称分配给任何控件的 DisplayMember,那么不幸的是,这将不起作用,因为 nameof 是编译时,然后应用混淆,另一方面,表达式主体成员名称来自第一篇文章将使用混淆,因为它是在运行时确定的 (4认同)
  • 顺便说一下,@ RaidenCore,您提到的应用早于C#,这就是为什么它们是用C ++编写的原因。如果他们是今天写的,谁知道使用哪种语言。参见例如Paint.NET。 (2认同)
  • 当您想在 WPF 中`RaiseProperty` 时,这非常有用!使用 RaisePropertyChanged(nameof(property)) 而不是 RaisePropertyChanged("property") (2认同)

Dan*_*haw 59

从这里使用GetMemberInfo:从lambda表达式中检索属性名称,您可以执行以下操作:

RemoteMgr.ExposeProperty(() => SomeClass.SomeProperty)

public class SomeClass
{
    public static string SomeProperty
    {
        get { return "Foo"; }
    }
}

public class RemoteMgr
{
    public static void ExposeProperty<T>(Expression<Func<T>> property)
    {
        var expression = GetMemberInfo(property);
        string path = string.Concat(expression.Member.DeclaringType.FullName,
            ".", expression.Member.Name);
        // Do ExposeProperty work here...
    }
}

public class Program
{
    public static void Main()
    {
        RemoteMgr.ExposeProperty("SomeSecret", () => SomeClass.SomeProperty);
    }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ant 17

有一个众所周知的hack从lambda表达式中提取它(这是来自PropertyObserver类,由Josh Smith在他的MVVM基础中):

    private static string GetPropertyName<TPropertySource>
        (Expression<Func<TPropertySource, object>> expression)
    {
        var lambda = expression as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        Debug.Assert(memberExpression != null, 
           "Please provide a lambda expression like 'n => n.PropertyName'");

        if (memberExpression != null)
        {
            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

        return null;
    }
Run Code Online (Sandbox Code Playgroud)

对不起,这个错过了一些上下文.这是一个更大的类的一部分,其中TPropertySource包含属性的类.您可以在TPropertySource中使函数通用,以从类中提取它.我建议看一下MVVM Foundation的完整代码.

  • 要进行此编译,您只需将方法签名更改为`public static string GetPropertyName <TPropertySource>(Expression <Func <TPropertySource,object >> expression)`然后调用如下:`var name = GetPropertyName <TestClass>(x = > x.Foo);` (2认同)

Jim*_*m C 16

好的,这是我最终创建的内容(根据我选择的答案和他引用的问题):

// <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;
 }
Run Code Online (Sandbox Code Playgroud)

用法:

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

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);
Run Code Online (Sandbox Code Playgroud)


Wil*_*ler 8

的PropertyInfo类应该可以帮助您实现这一点,如果我理解正确.

  1. Type.GetProperties()方法

    PropertyInfo[] propInfos = typeof(ReflectedType).GetProperties();
    propInfos.ToList().ForEach(p => 
        Console.WriteLine(string.Format("Property name: {0}", p.Name));
    
    Run Code Online (Sandbox Code Playgroud)

这是你需要的吗?


Rob*_*vey 6

您可以使用Reflection获取属性的实际名称.

http://www.csharp-examples.net/reflection-property-names/

如果您需要一种方法为属性分配"字符串名称",为什么不编写一个可以反映的属性来获取字符串名称?

[StringName("MyStringName")]
private string MyProperty
{
    get { ... }
}
Run Code Online (Sandbox Code Playgroud)


hyp*_*man 6

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

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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

string name = GetPropertyName(() => someObject.SomeProperty.SomeOtherProperty);
// returns "SomeProperty.SomeOtherProperty"
Run Code Online (Sandbox Code Playgroud)


Tho*_*mas 5

基于问题和本文中已有的答案:https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/我我提出我对这个问题的解决方案:

public static class PropertyNameHelper
{
    /// <summary>
    /// A static method to get the Propertyname String of a Property
    /// It eliminates the need for "Magic Strings" and assures type safety when renaming properties.
    /// See: http://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string
    /// </summary>
    /// <example>
    /// // Static Property
    /// string name = PropertyNameHelper.GetPropertyName(() => SomeClass.SomeProperty);
    /// // Instance Property
    /// string name = PropertyNameHelper.GetPropertyName(() => someObject.SomeProperty);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <param name="propertyLambda"></param>
    /// <returns></returns>
    public static 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;
    }
    /// <summary>
    /// Another way to get Instance Property names as strings.
    /// With this method you don't need to create a instance first.
    /// See the example.
    /// See: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/
    /// </summary>
    /// <example>
    /// string name = PropertyNameHelper((Firma f) => f.Firmenumsatz_Waehrung);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TReturn"></typeparam>
    /// <param name="expression"></param>
    /// <returns></returns>
    public static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        return body.Member.Name;
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一个测试,它还显示了实例和静态属性的用法:

[TestClass]
public class PropertyNameHelperTest
{
    private class TestClass
    {
        public static string StaticString { get; set; }
        public string InstanceString { get; set; }
    }

    [TestMethod]
    public void TestGetPropertyName()
    {
        Assert.AreEqual("StaticString", PropertyNameHelper.GetPropertyName(() => TestClass.StaticString));

        Assert.AreEqual("InstanceString", PropertyNameHelper.GetPropertyName((TestClass t) => t.InstanceString));
    }
}
Run Code Online (Sandbox Code Playgroud)


Jim*_*did 5

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

public static string GetPropertyName([CallerMemberName] String propertyName = null) {
  return propertyName;
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

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