英文:
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 ReflectedTypes 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论