Joel Abrahamsson
Joel Abrahamsson

Reputation: 721

How to pass the PropertyInfo of a property as parameter in a attribute?

Lets say I have two classes:

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

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

Note the stars in the property attribute in the second class. Would it somehow (using expressions I guess) be possible to specify A.Name in the SortBefore attribute? Note that I'm not after the value of Name in an instance of A but the PropertyInfo for the property Name in A so that I, when working with the PropertyInfo for Age in B, can retrieve the SortOrder value from it's superclass.

Upvotes: 1

Views: 1438

Answers (3)

Just to add context what Jon Skeet said: even in IL it isn't possible. Let's say, for kicks, you were able to obtain the MetadataToken for a property, by writing your own compiler, and injecting the property's metadata token into the attribute. At runtime you wouldn't be able to ask the module, in which the property is from, to resolve the metadata token; you'd receive this message:

This API does not support PropertyInfo tokens.

A way to test this is to get the PropertyInfo of any property, and ask the module which defines the type containing the property to ResolveMember, which accepts an int value of the metadata token, and feed it the PropertyInfo.MetadataToken:

Console.WriteLine(propInfo.DeclaringType.Module.ResolveMember(propInfo.MetadataToken));

The API wasn't designed for that purpose, properties are themselves just metadata that rides along with your program to help associate methods to a common context for use with compilers and IDEs. Once the compiler takes your code and does its magic, the property never shows up once in IL.

If you could push the property's MetadataToken into the attribute, the best thing you could do would be to also push the type's MetadataToken into the attribute, and have it retrieve the PropertyInfo object via means of iterating the type's properties, and the one with the matching MetadataToken would be your target.

It's crucial to understand that MetadataTokens are only unique within the scope of the module they exist within. I would say assembly, but multiple module assemblies kill that idea.

I only know as much as this from writing an ECMA-335 Metadata Parser.

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99869

Even the C# typeof operator is implemented by the compiler as a ldtoken followed by a call to Type.GetTypeFromHandle(). The PropertyInfo is a particularly interesting case because the ldtoken IL instruction can't take a Property metadata token as an argument, and there is no RuntimePropertyHandle type. However, the getter and/or setter methods can be obtained in IL via (this is not valid IL but shows the instructions). Unfortunately there is no direct way in C# to produce this code with the level of type safety that the typeof() operator provides.

ldtoken <method>
call MethodBase.GetMethodFromHandle

The answer to this earlier question shows how to get the PropertyInfo from the MethodInfo.

Jon's answer is correct about the solution you'll probably have to use.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500535

You can't, I'm afraid. It may be possible in IL - I'm not sure - but you can't do it in C#.

The closest you could come would be:

[SortBefore(typeof(A), "Name")]

and get the attribute to find the property at execution time. And yes, this is very brittle - if you do this, I'd add a unit test which finds all the attributes in an assembly and checks they're all valid.

Upvotes: 3

Related Questions