我有以下类型:
public abstract class Entity<TId>
{
public TId Id { get; set; }
}
public class Country : Entity<int>
{}
public class Language: Entity<int>
{}
我有以下的linq表达式方法:
internal static class ExpressionHelper
{
public static PropertyInfo HasKey<TEntityType, TKey>(Expression<Func<TEntityType, TKey>> keyDefinitionExpression)
{
LambdaExpression lambda = keyDefinitionExpression;
MemberExpression member = (MemberExpression)lambda.Body;
return member.Member as PropertyInfo;
}
}
我调用'GetProperty'来检索属性信息:
PropertyInfo idCountry = typeof(Country).GetProperty("Id");
PropertyInfo idLanguage = typeof(Language).GetProperty("Id");
其中:idCountry != idLanguage
有意义。但它们为什么不同呢?
2)
PropertyInfo countryIdProperty = ExpressionHelper.HasKey<Country, int>(c => c.Id);
PropertyInfo languageIdProperty = ExpressionHelper.HasKey<Language, int>(c => c.Id);
其中:countryIdProperty == languageIdProperty。= =比;为什么它们相同(相等)?
和idCountry != countryIdProperty。= =比;为什么它们不同?
更新:
public static PropertyInfo HasKey<TEntityType, TKey>(Expression<Func<TEntityType, TKey>> keyDefinitionExpression)
{
LambdaExpression lambda = keyDefinitionExpression;
MemberExpression member = (MemberExpression)lambda.Body;
Type callingType = typeof(TEntityType);
PropertyInfo pInfo = member.Member as PropertyInfo;
if (pInfo.ReflectedType != callingType)
{
return callingType.GetProperty(pInfo.Name);
}
return pInfo;
}
这样做安全吗?
由于您使用Country
和Language
类型的反射获得了前两个值,因此您得到了其ReflectedType
s绑定到这些类的实例。
后两个值是通过查看编译后的表达式树获得的。如果您要编写访问这些类之一的Id
属性的代码,您将看到它编译为对Entity<int>
类的属性的虚拟调用。
int Foo(Country c) => c.Id;
// Compiles to
IL_0000 ldarg.1
IL_0001 callvirt Entity <Int32>.get_Id ()
IL_0006 ret
属性访问本身并没有表明它是在不同的类上执行的,所以表达式树中属性的ReflectedType
是Entity<Int32>
,而不是Country
或Language
。
如果您想要一种更可靠的方法来确定两个属性是否引用相同的有效属性,您可以将MetadataToken
和Module
属性组合在一起。
Console.WriteLine((idCountry.MetadataToken, idCountry.Module) == (idLanguage.MetadataToken, idLanguage.Module)); // True