(수락 한 답변을 사용하여 만든 솔루션을 아래에서 참조하십시오)
리플렉션과 관련된 일부 코드의 유지 보수성을 개선하려고합니다. 이 앱에는 게시 된 원격 인터페이스에 포함되지 않은 앱의 일부에 액세스하기 위해 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"
.
답변
람다 식에서 추출하는 잘 알려진 해킹이 있습니다 (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의 클래스는 내가 제대로 이해한다면 당신은이를 달성하는 데 도움이됩니다.
-
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"