Get property value dynamically - c#

I have an object which has a huge number of properties. I'd like to get the value of each of those properties by simply looping through the properties collection of the object.
I've looked into the PropertyInfo.GetValue() method however it's not making much sense in the context I have.
Here's an example of what i'm trying to do (this code doesn't work btw):
foreach(var item in dataObjects)
{
foreach(PropertyInfo prop in item.GetType().GetProperties())
{
String value = prop.GetValue().ToString()
}
}
I realise now that getting the value of a property isn't this easy. What am I missing? I don't really understand what I need to pass to the GetValue() method because I simply want the value of the property I'm calling that method on.
Thanks for any help clarifying this for me. I've spent a couple of hours here just banging my head against the desk.

You need to provide the specific object on which you want to call the property in question:
prop.GetValue(item, null);
The PropertyInfo is just metatdata about the property on the type, not on the specific object instance. The PropertyInfo doesn't know which instance it came from (if any) - just the type/class it came from.
You can almost think of the PropertyInfo as just the name of the property. That's not enough information to do anything with it alone - we then have to say "get the value of the property with this name on... what?" On the object we provide.

PropertyInfo represents the property machinery itself (type, get method, set method, et cetera), not a property bound to a specific instance. If the property is nonstatic, you must provide an instance to read that property from -- that's the first parameter to GetValue. In other words, if pi is a PropertyInfo representing the Test property on some class and someObject is an instance of that class:
object a = someObject.Test;
object b = pi.GetValue(someObject, null);
both lines there get the value of the same property on the same object. If the property is static, you don't need to pass the instance, obviously (pass null instead). The second parameter is the index for indexed properties -- C# does not support indexed properties (it supports indexers, which are not exactly the same), so you will likely never need to pass anything but null for that second parameter unless you're working with some type from an assembly written in a language that does support indexed properties (like VB, I believe).

Related

C# Getting PropertyInfo within setter using PropertyBuilder

I'm attempting to write some .NET code that dynamically generates various types from a list of simple interfaces containing only property setters/getters. One of the types I would like to generate from the list is one that supports the given interfaces (with auto-generated backing fields) but that also tracks all property set operations, recording which properties got changed (and in the future possibly the time, context, user, etc. that made the change). After building samples in C# and examining them with ILDASM, I've got it working, but there is one part of the code for which the IL seems much more complicated than it should be. For this type, inside the code that defines the setter for a property, I set the value into the field (simple enough), but then I need to get the PropertyInfo for the property I'm setting (so later on a user can enumerate the PropertyInfos for the properties that were changed). In order to get the PropertyInfo for the property whose setter I'm in the middle of defining, I've got the following code (middle section):
...
PropertyBuilder pb = tb.DefineProperty(property.Name, property.Attributes, property.PropertyType, null);
MethodAttributes attr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
MethodBuilder setmb = tb.DefineMethod(SetPropertyMethodPrefix + property.Name, attr, null, new Type[] { property.PropertyType });
ILGenerator setgen = setmb.GetILGenerator();
...
// store the value in the backing field
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Ldarg_1);
setgen.Emit(OpCodes.Stfld, fb);
// get ready to give the change tracker the PropertyInfo for this property
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Ldfld, changeTrackerField);
// get the PropertyInfo for this property (there has to be a better way!)
setgen.Emit(OpCodes.Ldarg_0);
setgen.Emit(OpCodes.Call, typeof(object).GetMethod("GetType"));
// alternatively, instead of the two lines above, I can get the type token directly and get the type from there, which may or may not be any faster...
// setgen.Emit(OpCodes.Ldtoken, tb.TypeToken.Token);
// setgen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }));
setgen.Emit(OpCodes.Ldstr, property.Name);
setgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetProperty", new Type[] { typeof(string) }));
// give the PropertyInfo to our change tracking object
setgen.Emit(OpCodes.Callvirt, typeof(ChangeTracker).GetMethod("MarkPropertyChanged"));
setgen.Emit(OpCodes.Ret);
The middle section is equivalent to the C# code: GetType().GetProperty(<propertyName>), but it seems like there should be some faster way to get the PropertyInfo for the property I'm in the midst of building. The GetTypeFromHandle version seems like it may be more efficient (typeof(T) vs. this.GetType()), but I'm guessing there is a way to bypass GetProperty altogether, perhaps using PropertyBuilder.PropertyToken.
Is there a way to get the PropertyInfo instance for the property I'm in the middle of building without resorting to inserting IL code that does self-reflection?
I understand one would think there is some way to refer to a property (or an event) via its token in the method's body, but that's not possible. The only viable opcode would be ldtoken, but that only accepts methods, fields or types. I see your concerns, but I'd advise first doing some benchmarks, to see if calling GetProperty is really the performance bottleneck of the code. However, you have several other options to refer to the property.
Traverse all properties and check their token (emitted as an integer in the CIL).
Use a dictionary as a map from the property token to the actual PropertyInfo. Populate the dictionary in the constructor, or lazily.
Remember the order in which you build the properties, and use it to index the array returned by GetProperties. I suppose the order should be the same, but better check it.
To solve similar problems in the past I have created a statically-accessible Dictionary with the long being a simple, atomically-incremented unique ID. You can then retrieve the PropertyInfo - or any other object - using a static method call with the token you have created being hardcoded into the dynamic method.

What is System.Reflection.RuntimePropertyInfo and how do I compare it?

I was suprised to see that the actual type of the object I get with x.GetType().GetProperty("Foo") is not System.Reflection.PropertyInfo but System.Reflection.RuntimePropertyInfo.
I don't see this type documentation in msdn or elsewhere.
My actual problem grows from reference-comparing two properties. I receive a property from third-party lib and compare it with a property which I get with .GetProperty("Foo") on the same type. I expected properties to be the same object (and they looks like the same property in "Locals" window while debugging), but they are not (GetHashCode result is different). So, I think it can somehow be related with the actual type of the property object which is System.Reflection.RuntimePropertyInfo.
What is System.Reflection.RuntimePropertyInfo? How to compare it? Does it behaves the same as usual PropertyInfo?
RuntimePropertyInfo is an internal implementation. It is a PropertyInfo, and in fact, GetProperty returns PropertyInfo (even if the underlying type is RuntimePropertyInfo).
The third-party lib is probably getting the property of a different type than you are?
new blah().GetType().GetProperty("Test") == new blah().GetType().GetProperty("Test")
Returns true.
PropertyInfo is an abstract class while RuntimePropertyInfo is the concrete implementation of PropertyInfo.
When we call Type.GetProperties() or Type.GetProperty() they actually returns the RuntimePropertyInfo.
The reason you are getting reference not equal could be because of the Type signature difference in the third-party lib.

How to get the list of Enum properties of a class?

Closely related to How to get the list of properties of a class?, I've gotten as far as that question goes but I'm interested in knowing which of the returned properties are enumerations. My first (unlikely) guess was along the lines of:
foo A;
foreach (var property in A.GetType().GetProperties())
{
if (property.PropertyType is Enum)
//Celebrate
}
This did not work. It's valid, but Visual Studio was even able to warn in advance that "The given expression is never of the provided ('System.Enum') type".
To my understanding, C# Enums are wrappers over top of primitive counting types (defaulting with int, but also possibly byte, short, etc). I can easily test to see of the properties are of these types, but that will lead me to a lot of false positives in my search for Enums.
You are almost there. Just use
if (property.PropertyType.IsEnum)
// Celebrate
In .NET 4.5, you might need to get a TypeInfo object from the property type.
property is a PropertyInfo object.
PropertyInfo doesn't inherit Enum, so that can never be true.
You want to check the PropertyType – the Type object describing the property's return type.
if (property.PropertyType is Enum) won't work either, for the same reason – Type doesn't inherit Enum.
Instead, you need to look at the properties of the Type object to see whether it's an enum type.
In this case, you can just use its IsEnum property; in the more general case, you would want to call IsSubclassOf().

How to create a value type or string type object at runtime using Reflection

Probably simple but could not figure out. I am loading an assembly at runtime and browsing through some classes and generating input controls for its properties. To create an instance of an object at runtime I am using:
object o = PropertyType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes,null).Invoke(null);
and it works fine for class types. When the type is an array, I use
object o = PropertyType.Type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { 0 });
which also works fine. But when it comes to string type or value types GetConstructor.Invoke does not work. I also tried Activator.CreateInstance which also did not work.
What you're running into is that value types don't really have parameterless constructors. C# makes it look like they do, but they don't at the CLR level.
Activator.CreateInstance should work fine for real value types though:
object o = Activator.CreateInstance(typeof(int));
Console.WriteLine(o); // Prints 0
This will always give the default value for any value type.
Now, you're asking about strings - what string would you expect to create? The default value for the string type is null - but would you want the empty string instead? If so, you'll need to special-case that code.
If you want to be able to instantiate arbitrary objects with particular values, one thing you can check is if there is a TypeConverter that supports converting an instance (with the value you want to match) to an InstanceDescriptor. I'm not entirely sure what you're doing (your example suggests you're trying to create 'default' instances of the different objects), but just thought I'd mention this in case it's relevant. I use this in Emit code to emit arbitrary constant values to the stack via IL. Here's the snippet that gets the InstanceDescriptor:
var converter = TypeDescriptor.GetConverter(value);
if (converter.CanConvertTo(typeof (InstanceDescriptor)))
{
var desc = (InstanceDescriptor) converter.ConvertTo(value, typeof (InstanceDescriptor));
}
The descriptor specifies a means of constructing the instance, which could be calling a constructor, calling a static method, accessing a static property or accessing a static field. It also specifies whether the construction completely sets the value of the type to match your original instance; if not, you'll need to do additional reflection and setting of properties.
This is the mechanism that the WinForms Designer uses when generating the code-behind for the controls on the form, so it is supported for the common types that show up as properties of controls accessible from the designer.
The int type doesn't have any constructors.
The code you write is going to depend on the property's type; normally, you'd write special-case code for string, int and other primitive types.
Your code above contains the literal 0; how do you decide what values to pass to the constructors?

Is there a way to use ParameterInfo and PropertyInfo Interchangeably?

To me they are very similar structures. I was hoping there was a way to cast or convert one to the other easily.
I'm using reflection to do some magic. I've chosen the path to use parametrized constructors to create some user selected objects which they fill in values for the parameters using a UI.
The problem is one of the objects takes in a structure as a param and I can't get at the structures properties as parameter infos just property infos.
But I don't want to just reproduce the parameter info code I have now for property infos. It be nice if I could pass in a property info as a parameter info. Everything is really similar except for some names of some properties; ParameterType as opposed to PropertyType and what not.
I may have to do my own conversion or write my own class that houses the properties that I need and just use that custom object instead. Cheers.
No, there is not.
Those two classes represent two very different concepts.
A property is an attribute on an Type. The PropertyInfo class will allow you to set or get the value and will tell you additional information about the Property.
A parameter is an attribute of a method signature (an accessor on a type can have a parameter as well). The ParameterInfo class represents this concept and can tell you the Type of the parameter, the position in the method signature, whether it is an out or ref parameter, etc. See: MSDN doc. A ParameterInfo is not directly associated to a Type.

Categories

Resources