获取的属性名作为字符串获取的属性名作为字符串(Get name of property as a s

2019-05-10 10:36发布

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

我试图改善涉及反射一些代码的可维护性。 的应用程序有一个.NET远程接口暴露(除其他外)被称为执行用于访问不包含在其公布的远程接口的应用程序的各部分的方法。

下面是应用如何指定的属性(在这个例子中一个静态),其意思是访问通过执行:

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

因此,远程用户可以拨打电话:

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

和应用程序将使用反射来找到SomeClass.SomeProperty并返回它的值作为一个字符串。

不幸的是,如果有人重命名SomeProperty和忘记改变ExposeProperty()的第三PARM,它打破了这种机制。

我需要相当于:

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方法。 抛光的门把手是危险的工作...

感谢大家。

Answer 1:

从这里使用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);
    }
}


Answer 2:

在C#6.0中,这是现在一个非问题,你可以这样做:

nameof(SomeProperty)

这种表达在编译时间解决"SomeProperty"

nameof的MSDN文档 。



Answer 3:

有一个著名的黑客攻击,从lambda表达式(这是从PropertyObserver类,由约什 - 史密斯,在他的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;
    }

对不起,这是缺少一些背景。 这是一个较大的类,其中的一部分TPropertySource是包含属性的类。 你能在TPropertySource通用的函数从类提取它。 我建议考虑看看从完整的代码MVVM基金会 。



Answer 4:

好了,这是我结束了创建(基于我选择的答案,他所引用的问题):

// <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);


Answer 5:

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

  1. Type.GetProperties()方法

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

这是你需要什么?



Answer 6:

您可以使用反射来获得属性的实际名称。

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

如果您需要一种方式来分配“字符串名称”的属性,你为什么不写,你可以反映过来,以获取字符串名称的属性?

[StringName("MyStringName")]
private string MyProperty
{
    get { ... }
}


Answer 7:

我修改您的解决方案链在多个属性:

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"


Answer 8:

基于这已经是这个问题,本文就回答: 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;
    }
}

和测试也显示了实例和静态特性的用法:

[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));
    }
}


Answer 9:

老问题,但另一个回答这个问题是创建一个使用CallerMemberNameAttribute一个辅助类的静态函数。

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

然后使用它像:

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


Answer 10:

您可以使用堆栈跟踪类来得到当前函数的名称,(或者如果你把代码中的函数,然后下台的水平,并得到调用函数)。

见http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace(VS.71).aspx



Answer 11:

我一直在使用这个答案有很大的影响: 获取的财产,作为字符串,从一个Expression <Func键<TModel的,TProperty >>

我知道我已经回答了这个问题而回。 我对方的回答具有唯一的好处是,它适用于静态属性。 我找到的语法在这个答案更加有用,因为你不必创建要反映类型的变量。



Answer 12:

我不得不使用已经建议我的具体使用情况的解决方案有些难度,但想通了最后。 我不认为我的具体情况是值得一个新的问题,所以我在这里发布我的解决方案以供参考。 (这是非常密切相关的问题,并提供了其他任何人有类似情况矿溶液)。

我结束了看起来像这样的代码:

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这使得它更容易为其他开发人员能够得到它的权利。

我的解决方案和接受的答案之间的主要区别是,我的类是通用的,我只是要匹配泛型类型是布尔属性。



Answer 13:

这是我如何实现它,背后的原因是,如果你想要得到的名字来自它的成员的类不是静态的,那么你需要创建的,一个instanse,然后得到成员的姓名。 所以一般这里来帮助

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'


文章来源: Get name of property as a string