Programing

문자열로 속성 이름 가져 오기

lottogame 2020. 5. 17. 10:28
반응형

문자열로 속성 이름 가져 오기


(수락 한 답변을 사용하여 만든 솔루션을 아래에서 참조하십시오)

리플렉션과 관련된 일부 코드의 유지 보수성을 개선하려고합니다. 이 앱에는 게시 된 원격 인터페이스에 포함되지 않은 앱의 일부에 액세스하기 위해 Execute라는 방법을 노출시키는 .NET Remoting 인터페이스가 있습니다.

다음은 앱이 Execute를 통해 액세스 할 수있는 속성 (이 예제에서는 정적 속성)을 지정하는 방법입니다.

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

따라서 원격 사용자는 다음을 호출 할 수 있습니다.

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

그리고 앱은 리플렉션을 사용하여 SomeClass.SomeProperty를 찾고 그 값을 문자열로 반환합니다.

불행히도 누군가 누군가 SomeProperty의 이름을 바꾸고 ExposeProperty ()의 세 번째 매개 변수를 변경하는 것을 잊어 버린 경우이 메커니즘을 손상시킵니다.

나는 다음과 동등해야합니다.

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

리팩토링 도구는 이름 변경을 처리 할 수 ​​있도록 ExposeProperty에서 3 번째 매개 변수로 사용합니다.

이것을 할 수있는 방법이 있습니까? 미리 감사드립니다.

좋아, 내가 선택한 결과는 다음과 같습니다 (선택한 답변과 그가 언급 한 질문에 따라).

// <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 메서드를 단순화 할 차례입니다. 손잡이를 연마하는 것은 위험한 일입니다 ...

모두 감사합니다.


여기에서 GetMemberInfo를 사용하여 : 람다 식에서 속성 이름을 검색 하면 다음과 같이 할 수 있습니다.

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

C # 6.0을 사용하면 다음과 같이 할 수있는 문제가 아닙니다.

nameof(SomeProperty)

이 표현식은 컴파일 타임에로 해석됩니다 "SomeProperty".

nameof의 MSDN 설명서 .


람다 식에서 추출하는 잘 알려진 해킹이 있습니다 (MJVM의 Josh Smith가 PropertyObserver 클래스에서 가져온 것임).

    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 Foundation 에서 전체 코드를 살펴 보는 것이 좋습니다 .


좋아, 내가 선택한 결과는 다음과 같습니다 (선택한 답변과 그가 언급 한 질문에 따라).

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

PropertyInfo의 클래스는 내가 제대로 이해한다면 당신은이를 달성하는 데 도움이됩니다.

  1. Type.GetProperties () 메서드

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

이것이 당신이 필요한 것입니까?


Reflection을 사용하여 속성의 실제 이름을 얻을 수 있습니다.

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

속성에 "문자열 이름"을 할당하는 방법이 필요한 경우, 문자열 이름을 얻기 위해 반영 할 수있는 속성을 작성하지 않겠습니까?

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

여러 속성을 연결하도록 솔루션을 수정했습니다.

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"

이미 질문 과이 기사에있는 답변을 기반으로합니다 : https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/ I 이 문제에 대한 해결책을 제시하고 있습니다.

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

오래된 질문이지만이 질문에 대한 또 다른 대답은 CallerMemberNameAttribute를 사용하는 도우미 클래스에서 정적 함수를 만드는 것입니다.

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

그런 다음 다음과 같이 사용하십시오.

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

You can use the StackTrace class to get the name of the current function, (or if you put the code in a function, then step down a level and get the calling function).

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


I've been using this answer to great effect: Get the property, as a string, from an Expression<Func<TModel,TProperty>>

I realize I already answered this question a while back. The only advantage my other answer has is that it works for static properties. I find the syntax in this answer much more useful because you don't have to create a variable of the type you want to reflect.


I had some difficulty using the solutions already suggested for my specific use case, but figured it out eventually. I don't think my specific case is worthy of a new question, so I am posting my solution here for reference. (This is very closely related to the question and provides a solution for anyone else with a similar case to mine).

The code I ended up with looks like this:

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

The important part for me is that in the CompanyControl class the compiler will only allow me to choose a boolean property of ICompanyViewModel which makes it easier for other developers to get it right.

The main difference between my solution and the accepted answer is that my class is generic and I only want to match properties from the generic type that are boolean.


it's how I implemented it , the reason behind is if the class that you want to get the name from it's member is not static then you need to create an instanse of that and then get the member's name. so generic here comes to help

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

the usage is like this

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

참고URL : https://stackoverflow.com/questions/2820660/get-name-of-property-as-a-string

반응형