私のタイプのプロパティを指す式があります。ただし、すべてのプロパティタイプで機能するわけではありません。 「意味しない」とは、さまざまな式のタイプをもたらすことを意味します。 MemberExpression
になると思っていましたが、これは当てはまりません。
int
とGuid
の場合はUnaryExpression
になり、string
の場合はMemberExpression
になります。
私は少し混乱しています;)
私のクラス
_public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
_
テストコード
_Person p = new Person { Age = 16, Name = "John" };
Expression<Func<Person, object>> expression1 = x => x.Age;
// expression1.Body = UnaryExpression;
Expression<Func<Person, object>> expression2 = x => x.Name;
// expression2.Body = MemberExpression;
_
2つの式を比較して、それらが同じ型で同じプロパティを意味するかどうかを確認するにはどうすればよいですか?
ユーザーに感謝dasblinkenlight私を正しい軌道に乗せてくれた。
彼は方法を提供しました
_private static MemberExpression GetMemberExpression<T>(
Expression<Func<T,object>> exp
) {
var member = expr.Body as MemberExpression;
var unary = expr.Body as UnaryExpression;
return member ?? (unary != null ? unary.Operand as MemberExpression : null);
}
_
GetMemberExpression
メソッドの結果を比較し、GetMemberExpression().Member.Name
が同じかどうかを確認するために、次の拡張メソッドを作成しました。
_private static bool IsSameMember<T>(this Expression<Func<T, object>> expr1, Expression<Func<T, object>> expr2)
{
var result1 = GetMemberExpression(expr1);
var result2 = GetMemberExpression(expr2);
if (result1 == null || result2 == null)
return false;
return result1.Member.Name == result2.Member.Name;
}
_
これが発生する理由は、Age
がvalue型であるためです。値の型を返す式を_Func<Person,object>
_に強制するために、コンパイラは Convert(expr, typeof(object))
、a UnaryExpression
を挿入する必要があります=。
ただし、string
sおよびその他の参照型の場合、ボックス化する必要がないため、「ストレート」メンバー式が返されます。
MemberExpression
内のUnaryExpression
に到達したい場合は、そのオペランドを取得できます。
_private static MemberExpression GetMemberExpression<T>(
Expression<Func<T,object>> exp
) {
var member = exp.Body as MemberExpression;
var unary = exp.Body as UnaryExpression;
return member ?? (unary != null ? unary.Operand as MemberExpression : null);
}
_
Member.Name
文字列を比較するのではなく、PropertyInfo
インスタンスを直接比較して等しいかどうかを比較し、異なるクラスの2つのプロパティが同じ名前を共有する場合の誤検知を回避することをお勧めします。
public static bool IsSameProperty<TSourceA, TSourceB, TPropertyA, TPropertyB>(
Expression<Func<TSourceA, TPropertyA>> expA,
Expression<Func<TSourceB, TPropertyB>> expB)
{
MemberExpression memExpA = expA.Body as MemberExpression;
MemberExpression memExpB = expB.Body as MemberExpression;
if (memExpA == null || memExpB == null)
return false;
PropertyInfo propA = memExpA.Member as PropertyInfo;
PropertyInfo propB = memExpB.Member as PropertyInfo;
if (propA == null || propB == null)
return false;
return propA.Equals(propB);
}
Expression<Func<T, TResult>>
式のジェネリック型MemberExpression
として正しい値型(UnaryExpression
ではなく)を指定するだけで、ラムダ式がobject
ではなくTResult
としてコンパイルされるようにすることができます。
Expression<Func<Person, int>> expression1 = x => x.Age;
Expression<Func<Person, int>> expression2 = x => x.Age;
Expression<Func<Person, string>> expression3 = x => x.Name;
Console.WriteLine(IsSameProperty(expression1, expression2)); // True
Console.WriteLine(IsSameProperty(expression1, expression3)); // False