不同情境下检索到的PropertyInfo之间有何区别?

huangapple go评论52阅读模式
英文:

What's the differerence between PropertyInfo(s) retrieved from different scenarios

问题

  1. 我调用 '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&lt;TId&gt;
{
   public TId Id { get; set; }
}

public class Country : Entity&lt;int&gt;
{}
public class Language: Entity&lt;int&gt;
{}

And I have the following linq expression method:

internal static class ExpressionHelper
{
   public static PropertyInfo HasKey&lt;TEntityType, TKey&gt;(Expression&lt;Func&lt;TEntityType, TKey&gt;&gt; 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(&quot;Id&quot;);
PropertyInfo idLanguage = typeof(Language).GetProperty(&quot;Id&quot;);

Where: idCountry != idLanguage

It makes sense. But why are they different?

PropertyInfo countryIdProperty = ExpressionHelper.HasKey&lt;Country, int&gt;(c =&gt; c.Id);
PropertyInfo languageIdProperty = ExpressionHelper.HasKey&lt;Language, int&gt;(c =&gt; c.Id);

Where: countryIdProperty == languageIdProperty. ==> Why are they the same (equal)?

And idCountry != countryIdProperty. ==> Why are they different?


Updates:

public static PropertyInfo HasKey&lt;TEntityType, TKey&gt;(Expression&lt;Func&lt;TEntityType, TKey&gt;&gt; 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&lt;int&gt; class.

int Foo(Country c) =&gt; c.Id;
// Compiles to
IL_0000	ldarg.1	
IL_0001	callvirt	Entity &lt;Int32&gt;.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&lt;Int32&gt;, 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

huangapple
  • 本文由 发表于 2023年4月11日 05:52:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/75981014.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定