如何将属性的PropertyInfo作为参数传递给属性?

时间:2009-07-17 06:21:07

标签: .net reflection lambda

假设我有两个班级:

class A
{
   [SortOrder(3)]
   public string Name { get; set; }
}

class B : A
{
   [SortBefore(*****)]
   public string Age { get; set; }
}

注意第二个类中属性属性中的星号。它会以某种方式(使用表达式我猜)可以在SortBefore属性中指定A.Name吗?请注意,我不是在A的实例中使用Name的值,而是在A中的属性Name的PropertyInfo之后,因此当使用B中的AgeIn属性信息时,我可以从它的超类中检索SortOrder值。

3 个答案:

答案 0 :(得分:3)

你不能,我害怕。在IL中可能可能 - 我不确定 - 但你不能用C#来做。

你最接近的可能是:

[SortBefore(typeof(A),“Name”)]

并获取属性以在执行时查找属性。是的,这非常脆弱 - 如果你这样做,我会添加一个单元测试,它可以找到一个程序集中的所有属性并检查它们是否全部有效。

答案 1 :(得分:1)

即使C#typeof运算符也由编译器实现为ldtoken,然后调用Type.GetTypeFromHandle()PropertyInfo是一个特别有趣的情况,因为ldtoken IL指令不能将Property元数据标记作为参数,并且没有RuntimePropertyHandle类型。但是,getter和/或setter方法可以通过IL获得(这不是有效的IL,但显示了指令)。遗憾的是,C#没有直接的方法来生成具有typeof()运算符提供的类型安全级别的代码。

ldtoken <method>
call MethodBase.GetMethodFromHandle

this earlier question的答案显示了如何从MethodInfo获取PropertyInfo。

Jon对你可能不得不使用的解决方案的回答是正确的。

答案 2 :(得分:0)

只是为了添加Jon Skeet所说的语境:即使在IL中也是不可能的。让我们说,对于kicks,您可以通过编写自己的编译器并将属性的元数据标记注入属性来获取属性的MetadataToken。在运行时,您将无法询问属性所在的模块来解析元数据令牌;你会收到这条消息:

  

此API不支持PropertyInfo令牌。

测试此方法的一种方法是获取任何属性的PropertyInfo,并询问定义包含属性的类型的模块ResolveMember,该模块接受int的值PropertyInfo.MetadataToken元数据令牌,并将其提供给Console.WriteLine(propInfo.DeclaringType.Module.ResolveMember(propInfo.MetadataToken));

MetadataToken

API不是为此目的而设计的,属性本身就是与您的程序一起使用的元数据,以帮助将方法与公共上下文相关联,以便与编译器和IDE一起使用。一旦编译器接受了你的代码并发挥其魔力,该属性永远不会在IL中显示一次。

如果您可以将属性的MetadataToken推送到属性中,那么您可以做的最好的事情就是将类型的PropertyInfo推送到属性中,并让它检索MetadataToken对象通过迭代类型的属性,匹配MetadataToken的对象将成为您的目标。

理解{{1}}仅在其所在模块的范围内是唯一的,这一点至关重要。我会说汇编,但是多个模块组件会破坏这个想法。

我只能通过编写ECMA-335元数据解析器来了解这一点。