我有以下类型:
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
与这些类相关的实例。
后两个值是通过查看编译的表达式树获得的。如果您要编写访问其中一个类的
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