람다 표현식을 통해 전달 될 때 속성 이름을 얻는 더 좋은 방법이 있습니까? 여기 제가 현재 가지고있는 것이 있습니다.
예.
GetSortingInfo<User>(u => u.UserId);
속성이 문자열 일 때만 memberexpression으로 캐스팅했습니다. 모든 속성이 문자열이 아니기 때문에 객체를 사용해야했지만 그 대신 단항식을 반환합니다.
public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var expression = GetMemberInfo(action);
string name = expression.Member.Name;
return GetInfo(html, name);
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr =
((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null)
throw new ArgumentException("method");
return memberExpr;
}
최근에는 형식이 안전한 OnPropertyChanged 메서드를 만들기 위해 매우 비슷한 작업을 수행했습니다.
다음은 표현식에 대한 PropertyInfo 객체를 반환하는 메소드입니다. 표현식이 속성이 아닌 경우 예외를 throw합니다.
public PropertyInfo GetPropertyInfo<TSource, TProperty>(
TSource source,
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
그만큼source
매개 변수는 컴파일러가 메서드 호출에 대한 형식 유추를 수행 할 수 있도록 사용됩니다. 당신은 다음을 할 수 있습니다.
var propertyInfo = GetPropertyInfo(someUserObject, u => u.UserID);
if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType) && !propInfo.ReflectedType.IsAssignableFrom(type))
인터페이스도 허용합니다. - Graham Kingif(!propInfo.ReflectedType.IsAssignableFrom(type))
? - Connell
소스와 속성을 강력하게 입력하고 람다에 대한 입력을 명시 적으로 추측하는 것이 다른 방법을 찾았습니다. 정확한 용어인지는 확실하지 않지만 결과는 여기에 있습니다.
public static RouteValueDictionary GetInfo<T,P>(this HtmlHelper html, Expression<Func<T, P>> action) where T : class
{
var expression = (MemberExpression)action.Body;
string name = expression.Member.Name;
return GetInfo(html, name);
}
그런 다음 그렇게 부르십시오.
GetInfo((User u) => u.UserId);
그리고 그것은 작동합니다.
모두에게 감사드립니다.
GetInfo(nameof(u.UserId))
- Vladislav
나는 같은 일로 놀고 있었고 이것을 해결했다. 완전히 테스트되지는 않았지만 값 유형 (이 문제를 다루는 단항식 문제)을 처리하는 것처럼 보입니다.
public static string GetName(Expression<Func<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;
}
o => o.Thing1.Thing2
돌아올거야.Thing2
, 아니라Thing1.Thing2
, EntityFramework에서 사용하려는 경우 올바르지 않습니다. - drzaus
public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
return (Field.Body as MemberExpression ?? ((UnaryExpression)Field.Body).Operand as MemberExpression).Member.Name;
}
이는 멤버 및 단항 식을 처리합니다. 차이점은UnaryExpression
표현식이 값 유형을 나타내지 만MemberExpression
표현식이 참조 유형을 나타내는 경우 모든 것은 객체에 캐스트 될 수 있지만 값 유형은 박스 처리되어야합니다. 이것이 단항 표현이 존재하는 이유입니다.참고.
가독성을 위해 (@Jowen) 다음은 확장 된 기능입니다.
public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
if (object.Equals(Field, null))
{
throw new NullReferenceException("Field is required");
}
MemberExpression expr = null;
if (Field.Body is MemberExpression)
{
expr = (MemberExpression)Field.Body;
}
else if (Field.Body is UnaryExpression)
{
expr = (MemberExpression)((UnaryExpression)Field.Body).Operand;
}
else
{
const string Format = "Expression '{0}' not supported.";
string message = string.Format(Format, Field);
throw new ArgumentException(message, "Field");
}
return expr.Member.Name;
}
가장 중요한 경우는Array
.길이. '길이'는 속성으로 표시되지만 이전에 제안 된 솔루션에서는 사용할 수 없습니다.
using Contract = System.Diagnostics.Contracts.Contract;
using Exprs = System.Linq.Expressions;
static string PropertyNameFromMemberExpr(Exprs.MemberExpression expr)
{
return expr.Member.Name;
}
static string PropertyNameFromUnaryExpr(Exprs.UnaryExpression expr)
{
if (expr.NodeType == Exprs.ExpressionType.ArrayLength)
return "Length";
var mem_expr = expr.Operand as Exprs.MemberExpression;
return PropertyNameFromMemberExpr(mem_expr);
}
static string PropertyNameFromLambdaExpr(Exprs.LambdaExpression expr)
{
if (expr.Body is Exprs.MemberExpression) return PropertyNameFromMemberExpr(expr.Body as Exprs.MemberExpression);
else if (expr.Body is Exprs.UnaryExpression) return PropertyNameFromUnaryExpr(expr.Body as Exprs.UnaryExpression);
throw new NotSupportedException();
}
public static string PropertyNameFromExpr<TProp>(Exprs.Expression<Func<TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);
return PropertyNameFromLambdaExpr(expr);
}
public static string PropertyNameFromExpr<T, TProp>(Exprs.Expression<Func<T, TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);
return PropertyNameFromLambdaExpr(expr);
}
예제 사용법 :
int[] someArray = new int[1];
Console.WriteLine(PropertyNameFromExpr( () => someArray.Length ));
만약PropertyNameFromUnaryExpr
확인하지 않았다.ArrayLength
, "someArray"는 콘솔에 출력 될 것입니다 (컴파일러는 백킹 길이에 대한 직접 액세스를 생성하는 것으로 보입니다들, 최적화, 심지어는 디버그에서, 따라서 특별한 경우).
struct / class / interface / delegate / array의 fields / properties / indexers / methods / extension methods / delegate의 문자열 이름을 가져 오기위한 일반적인 구현입니다. 나는 static / instance와 non-generic / generic 변형의 조합으로 테스트했다.
//involves recursion
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null; //recursive func
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};
return nameSelector(memberSelector.Body);
}
이 것은 간단한 것으로 쓰여질 수 있습니다.while
너무 루프 :
//iteration based
public static string GetMemberName(this LambdaExpression memberSelector)
{
var currentExpression = memberSelector.Body;
while (true)
{
switch (currentExpression.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)currentExpression).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)currentExpression).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)currentExpression).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
currentExpression = ((UnaryExpression)currentExpression).Operand;
break;
case ExpressionType.Invoke:
currentExpression = ((InvocationExpression)currentExpression).Expression;
break;
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
}
}
나는 재귀 적 접근법을 좋아하지만, 두 번째 것은 읽기 쉽다. 하나는 다음과 같이 부를 수 있습니다.
someExpr = x => x.Property.ExtensionMethod()[0]; //or
someExpr = x => Static.Method().Field; //or
someExpr = x => VoidMethod(); //or
someExpr = () => localVariable; //or
someExpr = x => x; //or
someExpr = x => (Type)x; //or
someExpr = () => Array[0].Delegate(null); //etc
string name = someExpr.GetMemberName();
마지막 멤버를 인쇄합니다.
노트 :
체인 식의 경우A.B.C
, "C"가 반환됩니다.
이것은 다음과 함께 작동하지 않습니다.const
배열 인덱서 또는enum
s (모든 경우를 커버하는 것은 불가능 함).
여기에 대한 업데이트가 있습니다.카메론이 제안한 방법. 첫 x 째 매개 변수는 필요하지 않습니다.
public PropertyInfo GetPropertyInfo<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
다음을 수행 할 수 있습니다.
var propertyInfo = GetPropertyInfo<SomeType>(u => u.UserID);
var propertyInfo = GetPropertyInfo((SomeType u) => u.UserID);
확장 메소드 :
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
return GetPropertyInfo(propertyLambda);
}
public static string NameOfProperty<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
PropertyInfo prodInfo = GetPropertyInfo(propertyLambda);
return prodInfo.Name;
}
할 수있는 일 :
SomeType someInstance = null;
string propName = someInstance.NameOfProperty(i => i.Length);
PropertyInfo propInfo = someInstance.GetPropertyInfo(i => i.Length);
나는 그 중 일부가제안 된 답변그것은MemberExpression
/UnaryExpression
중첩 된 / 하위 속성을 캡처하지 않습니다.
전의)o => o.Thing1.Thing2
보고Thing1
오히려Thing1.Thing2
.
이 구별은 EntityFramework로 작업하려고 할 때 중요합니다.DbSet.Include(...)
.
나는 단지 구문 분석하는 것을 발견했다.Expression.ToString()
비교적 빨리 잘 작동하는 것 같습니다. 나는 그것을UnaryExpression
버전, 심지어 점점ToString
~의Member/UnaryExpression
그것이 더 빠르지 만, 그 차이는 무시할 만하다. 이것이 끔찍한 생각이라면 저를 시정하십시오.
/// <summary>
/// Given an expression, extract the listed property name; similar to reflection but with familiar LINQ+lambdas. Technique @via https://stackoverflow.com/a/16647343/1037948
/// </summary>
/// <remarks>Cheats and uses the tostring output -- Should consult performance differences</remarks>
/// <typeparam name="TModel">the model type to extract property names</typeparam>
/// <typeparam name="TValue">the value type of the expected property</typeparam>
/// <param name="propertySelector">expression that just selects a model property to be turned into a string</param>
/// <param name="delimiter">Expression toString delimiter to split from lambda param</param>
/// <param name="endTrim">Sometimes the Expression toString contains a method call, something like "Convert(x)", so we need to strip the closing part from the end</param>
/// <returns>indicated property name</returns>
public static string GetPropertyName<TModel, TValue>(this Expression<Func<TModel, TValue>> propertySelector, char delimiter = '.', char endTrim = ')') {
var asString = propertySelector.ToString(); // gives you: "o => o.Whatever"
var firstDelim = asString.IndexOf(delimiter); // make sure there is a beginning property indicator; the "." in "o.Whatever" -- this may not be necessary?
return firstDelim < 0
? asString
: asString.Substring(firstDelim+1).TrimEnd(endTrim);
}//-- fn GetPropertyNameExtended
(구분 기호를 확인하는 것은 과도 함일 수 있음)
데모 + 비교 코드 -https://gist.github.com/zaus/6992590
o => o.Thing1.Thing2
돌아 오지 않았습니다.Thing1
네가 말한대로Thing2
. 사실 당신의 대답은 다음과 같습니다.Thing1.Thing2
수도 있고 그렇지 않을 수도 있습니다. - nawfalThing1.Thing2
결코Thing1
. 나는 말했다Thing2
의미하는값의o.Thing1.Thing2
이것은 술어의 요점입니다. 그 의도를 반영하도록 답변을 업데이트하겠습니다. - drzaus
음, 전화 할 필요가 없습니다..Name.ToString()
, 넓게는 그것에 관한 것입니다, 그렇습니다. 필요한 유일한 고려 사항은x.Foo.Bar
"Foo", "Bar"또는 예외를 반환해야합니다. 즉, 반복 할 필요가 있습니다.
유연한 정렬에 대한 자세한 내용은 (re comment)을 참조하십시오.이리.
나는 C #6 이전 프로젝트를위한 확장 메소드를 사용하고있다.의 이름()C #6을 목표로하는 사람들에게.
public static class MiscExtentions
{
public static string NameOf<TModel, TProperty>(this object @object, Expression<Func<TModel, TProperty>> propertyExpression)
{
var expression = propertyExpression.Body as MemberExpression;
if (expression == null)
{
throw new ArgumentException("Expression is not a property.");
}
return expression.Member.Name;
}
}
그리고 저는 그것을 다음과 같이 부릅니다 :
public class MyClass
{
public int Property1 { get; set; }
public string Property2 { get; set; }
public int[] Property3 { get; set; }
public Subclass Property4 { get; set; }
public Subclass[] Property5 { get; set; }
}
public class Subclass
{
public int PropertyA { get; set; }
public string PropertyB { get; set; }
}
// result is Property1
this.NameOf((MyClass o) => o.Property1);
// result is Property2
this.NameOf((MyClass o) => o.Property2);
// result is Property3
this.NameOf((MyClass o) => o.Property3);
// result is Property4
this.NameOf((MyClass o) => o.Property4);
// result is PropertyB
this.NameOf((MyClass o) => o.Property4.PropertyB);
// result is Property5
this.NameOf((MyClass o) => o.Property5);
필드와 속성 모두에서 잘 작동합니다.
C #7 패턴 매칭 :
public static string GetMemberName<T>(this Expression<T> expression)
{
switch (expression.Body)
{
case MemberExpression m:
return m.Member.Name;
case UnaryExpression u when u.Operand is MemberExpression m:
return m.Member.Name;
default:
throw new NotImplementedException(expression.GetType().ToString());
}
}
예:
public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var name = action.GetMemberName();
return GetInfo(html, name);
}
기본 메서드는 문자열 만 허용하기 때문에 형식 안전 방식으로 수정 된대로 Entity Framework POCO 클래스의 속성에 플래그를 지정할 수 있도록 ObjectStateEntry에 대한 확장 메서드를 만들었습니다. 속성에서 이름을 얻는 내 방식은 다음과 같습니다.
public static void SetModifiedProperty<T>(this System.Data.Objects.ObjectStateEntry state, Expression<Func<T>> action)
{
var body = (MemberExpression)action.Body;
string propertyName = body.Member.Name;
state.SetModifiedProperty(propertyName);
}
나는 그 일을했다.INotifyPropertyChanged
아래의 방법과 유사한 구현. 여기서 속성은 아래에 표시된 기본 클래스의 사전에 저장됩니다. 상속을 사용하는 것이 항상 바람직한 것은 아니지만 뷰 모델의 경우 뷰 모델 클래스에서 매우 깨끗한 속성 참조를 허용하고 받아 들일 수 있다고 생각합니다.
public class PhotoDetailsViewModel
: PropertyChangedNotifierBase<PhotoDetailsViewModel>
{
public bool IsLoading
{
get { return GetValue(x => x.IsLoading); }
set { SetPropertyValue(x => x.IsLoading, value); }
}
public string PendingOperation
{
get { return GetValue(x => x.PendingOperation); }
set { SetPropertyValue(x => x.PendingOperation, value); }
}
public PhotoViewModel Photo
{
get { return GetValue(x => x.Photo); }
set { SetPropertyValue(x => x.Photo, value); }
}
}
다소 복잡한 기본 클래스가 아래에 나와 있습니다. 람다 식에서 속성 이름으로의 변환을 처리합니다. 이름 만 사용되기 때문에 속성은 실제로는 의사 속성이라는 점에 유의하십시오. 그러나 뷰 모델에는 투명하게 보이고 뷰 모델에는 속성에 대한 참조가 표시됩니다.
public class PropertyChangedNotifierBase<T> : INotifyPropertyChanged
{
readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
protected U GetValue<U>(Expression<Func<T, U>> property)
{
var propertyName = GetPropertyName(property);
return GetValue<U>(propertyName);
}
private U GetValue<U>(string propertyName)
{
object value;
if (!_properties.TryGetValue(propertyName, out value))
{
return default(U);
}
return (U)value;
}
protected void SetPropertyValue<U>(Expression<Func<T, U>> property, U value)
{
var propertyName = GetPropertyName(property);
var oldValue = GetValue<U>(propertyName);
if (Object.ReferenceEquals(oldValue, value))
{
return;
}
_properties[propertyName] = value;
RaisePropertyChangedEvent(propertyName);
}
protected void RaisePropertyChangedEvent<U>(Expression<Func<T, U>> property)
{
var name = GetPropertyName(property);
RaisePropertyChangedEvent(name);
}
protected void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private static string GetPropertyName<U>(Expression<Func<T, U>> property)
{
if (property == null)
{
throw new NullReferenceException("property");
}
var lambda = property as LambdaExpression;
var memberAssignment = (MemberExpression) lambda.Body;
return memberAssignment.Member.Name;
}
public event PropertyChangedEventHandler PropertyChanged;
}
public bool IsLoading { get { return GetValue(MethodBase.GetCurrentMethod().Name); } set { SetPropertyValue(MethodBase.GetCurrentMethod().Name, value); } }
. 더 느리지 만보다 일반적이고 간단합니다. - nawfal
이것은 또 다른 대답입니다.
public static string GetPropertyName<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
return metaData.PropertyName;
}
ModelMetadata
에 존재하다System.Web.Mvc
네임 스페이스. 일반적인 경우에는 적합하지 않을 수 있습니다. - asakura89
배수 필드를 가져 오려면이 함수를 그대로 두십시오.
/// <summary>
/// Get properties separated by , (Ex: to invoke 'd => new { d.FirstName, d.LastName }')
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
public static string GetFields<T>(Expression<Func<T, object>> exp)
{
MemberExpression body = exp.Body as MemberExpression;
var fields = new List<string>();
if (body == null)
{
NewExpression ubody = exp.Body as NewExpression;
if (ubody != null)
foreach (var arg in ubody.Arguments)
{
fields.Add((arg as MemberExpression).Member.Name);
}
}
return string.Join(",", fields);
}
PropertyInfo를 기반으로하는 다른 방법은 다음과 같습니다.이 대답.그것은 객체 인스턴스에 대한 필요성을 제거합니다.
/// <summary>
/// Get metadata of property referenced by expression. Type constrained.
/// </summary>
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
return GetPropertyInfo((LambdaExpression) propertyLambda);
}
/// <summary>
/// Get metadata of property referenced by expression.
/// </summary>
public static PropertyInfo GetPropertyInfo(LambdaExpression propertyLambda)
{
// https://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if(propertyLambda.Parameters.Count() == 0)
throw new ArgumentException(String.Format(
"Expression '{0}' does not have any parameters. A property expression needs to have at least 1 parameter.",
propertyLambda.ToString()));
var type = propertyLambda.Parameters[0].Type;
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(String.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
다음과 같이 호출 할 수 있습니다.
var propertyInfo = GetPropertyInfo((User u) => u.UserID);
나는 업데이트했다.@ 카메론의 대답에 대한 몇 가지 안전 점검을 포함Convert
형식화 된 람다 식 :
PropertyInfo GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
var body = propertyLambda.Body;
if (!(body is MemberExpression member)
&& !(body is UnaryExpression unary
&& (member = unary.Operand as MemberExpression) != null))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"does not refer to a property.");
if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"refers to a field, not a property.");
var type = typeof(TSource);
if (!propInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' " +
"refers to a property that is not from type '{type}'.");
return propInfo;
}
.NET 4.0부터는 다음을 사용할 수 있습니다.ExpressionVisitor
속성 찾기 :
class ExprVisitor : ExpressionVisitor {
public bool IsFound { get; private set; }
public string MemberName { get; private set; }
public Type MemberType { get; private set; }
protected override Expression VisitMember(MemberExpression node) {
if (!IsFound && node.Member.MemberType == MemberTypes.Property) {
IsFound = true;
MemberName = node.Member.Name;
MemberType = node.Type;
}
return base.VisitMember(node);
}
}
이 방문자를 사용하는 방법은 다음과 같습니다.
var visitor = new ExprVisitor();
visitor.Visit(expr);
if (visitor.IsFound) {
Console.WriteLine("First property in the expression tree: Name={0}, Type={1}", visitor.MemberName, visitor.MemberType.FullName);
} else {
Console.WriteLine("No properties found.");
}
MemberExpression
여기에 나열된 접근 방식은이름회원의아니실제를 얻으려면MemberInfo
그 자체, 왜냐하면MemberInfo
돌려 주어지는 것은, 특정의 "dervied : base"의 리후 레크 트 된 형태가되는 것이 보증되지 않습니다. 시나리오. 만나다lambda-expression-not-returning-expected-memberinfo. 한 번 날 속였다. 받아 들여진 응답은 이것으로 너무 고통받습니다. - nawfal