[C#] 문자열로 속성 이름 가져 오기

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

리플렉션과 관련된 일부 코드의 유지 보수성을 개선하려고합니다. 이 앱에는 게시 된 원격 인터페이스에 포함되지 않은 앱의 일부에 액세스하기 위해 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"