英文:
What's the differerence between PropertyInfo(s) retrieved from different scenarios
问题
-
我调用 'GetProperty' 来检索属性信息:
PropertyInfo idCountry = typeof(Country).GetProperty("Id");
PropertyInfo idLanguage = typeof(Language).GetProperty("Id");
其中:idCountry 不等于 idLanguage。这是有道理的。但为什么它们不同?
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;
}
这种方法安全吗?
英文:
I have the following types:
public abstract class Entity<TId>
{
public TId Id { get; set; }
}
public class Country : Entity<int>
{}
public class Language: Entity<int>
{}
And I have the following linq expression method:
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;
}
}
I call 'GetProperty' to retrieve the property info:
PropertyInfo idCountry = typeof(Country).GetProperty("Id");
PropertyInfo idLanguage = typeof(Language).GetProperty("Id");
Where: idCountry != idLanguage
It makes sense. But why are they different?
PropertyInfo countryIdProperty = ExpressionHelper.HasKey<Country, int>(c => c.Id);
PropertyInfo languageIdProperty = ExpressionHelper.HasKey<Language, int>(c => c.Id);
Where: countryIdProperty == languageIdProperty. ==> Why are they the same (equal)?
And idCountry != countryIdProperty. ==> Why are they different?
Updates:
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;
}
Is it the safe way to do it?
答案1
得分: 1
Since you acquired the first two values using reflection off of the Country
and Language
types, you got instances whose ReflectedType
(https://learn.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo.reflectedtype?view=net-6.0) is tied to those classes.
The second two values were obtained by looking at a compiled expression tree. If you were to write code that accesses the Id
property of one of these classes, you'd see that it compiles to a virtual call to the property on the Entity<int>
class.
int Foo(Country c) => c.Id;
// Compiles to
IL_0000 ldarg.1
IL_0001 callvirt Entity<int>.get_Id()
IL_0006 ret
There's nothing about the property access itself to indicate it's being performed on a different class, so the ReflectedType
on the property in the expression tree is Entity<int>
, rather than Country
or Language
.
If you want a more reliable way to determine whether two properties refer to the same effective property, you can combine the MetadataToken
(https://learn.microsoft.com/en-us/dotnet/api/system.reflection.memberinfo.metadatatoken?view=net-6.0) and Module
properties.
Console.WriteLine((idCountry.MetadataToken, idCountry.Module) == (idLanguage.MetadataToken, idLanguage.Module)); // True
英文:
Since you acquired the first two values using reflection off of the Country
and Language
types, you got instances whose ReflectedType
s are tied to those classes.
The second two values were obtained by looking at a compiled expression tree. If you were to write code that accesses the Id
property of one of these classes, you'd see that it compiles to a virtual call to the property on the Entity<int>
class.
int Foo(Country c) => c.Id;
// Compiles to
IL_0000 ldarg.1
IL_0001 callvirt Entity <Int32>.get_Id ()
IL_0006 ret
There's nothing about the property access itself to indicate it's being performed on a different class, so the ReflectedType
on the property in the expression tree is Entity<Int32>
, rather than Country
or Language
.
If you want a more reliable way to determine whether two properties refer to the same effective property, you can combine the MetadataToken
and Module
properties.
Console.WriteLine((idCountry.MetadataToken, idCountry.Module) == (idLanguage.MetadataToken, idLanguage.Module)); // True
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论