C# Getting PropertyInfo within setter using PropertyBuilder - c#

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.

Related

How can I determine the target type for a markup extension return value?

I am writing a custom markup extension.
In its ProvideValue method, I would like to modify/convert my return value based upon the intended target type of the property that the markup extension is being used to supply a value for.
(Basically, a TypeConverter knows about the target type of its surrounding binding and can adapt its behaviour accordingly; I would like to do the same in my markup extension.)
Now, the ProvideValue method only receives an IServiceProvider as an argument.
It seems I should be able to use it to get an object that provides me with the desired bit of context information, but so far, none of my attempts to do so has been entirely satisfying:
I have retrieved an IDestinationTypeProvider implementation. While it appears to do exactly what I need, based upon its name, unfortunately, it throws an exception:
var dtp = (IDestinationTypeProvider)serviceProvider.GetService(typeof(IDestinationTypeProvider));
var destType = dtp.GetDestinationType(); // NullReferenceException on this line
I have retrieved an IProvideValueTarget implementation. It supplies me with the target property, but only as a System.Object, so it seems I have to prepare my code myself for treating different (?) kinds of properties and retrieving the type myself.
What is the intended way for a markup extension to get its target type?
Use the IServiceProvider to get yourself an IProvideValueTarget, then look at TargetProperty, which should (but is not guaranteed to) be a DependencyProperty.
var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
var propertyType = (provideValueTarget.TargetProperty as DependencyProperty)?.PropertyType;
// Test propertyType for null
The target property might also be an EventInfo if the MarkupExtension is used with an event, or a MethodInfo if it's used with an attached event (or, as you pointed out in the comments, a PropertyInfo if it's used with a normal property).
Unfortunately I think this is the only way of doing this. DynamicResourceExtension has similar checks, see here and here - if there was a better API, I assume it would be using it.

Given an object that I happen to know is a System.RuntimeType how do I get a typed object out?

I've done some hideous DI reflection :(
I've gotten a FieldInfo object and called GetValue() on it.
I get an object back.
Examining this object in VisualStudio, I discover that it is a "prototype", and that GetType() returns System.RuntimeType.
In the immediate window, I can cast my object as System.RuntimeType, and then I discover an AsType() method, which returns me my real, typed object.
Unfortunately, when try to write this in my code, I'm told that System.RuntimeType is an internal type, and thus I can't use it :(.
How can I get a typed object out of this object?
Full code:
KernelBase baseKernel = (KernelBase)ninjectKernel;
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
FieldInfo field = typeof(KernelBase).GetField("bindings", flags);
Multimap<Type, IBinding> allBindingsPerTypeMap = (Multimap<Type, IBinding>)field.GetValue(baseKernel);
var aBinding = allInterfaceTypesWithAllBindings.First(pair => pair.InterfaceType.Name.Contains("FilePath")).Binding;
var aBindingTarget = aBinding .BindingConfiguration.ProviderCallback.Target;
var prototype = aBindingTarget.GetType().GetField("prototype").GetValue(aBindingTarget);
// prototype is an object, which I'd like to turn into a real type.
var runtimeType = prototype.GetType(); // this returns System.RuntimeType
Note that I genuinely don't actually know what the type of the object is - the thing I'm reflecting on, is itself a piece of reflection ... I'm trying to extract binding info from my DI framework.
Solutions to the root problem are useful, but I do actually want to know how to interact with this System.RuntimeType object.
UPDATE:
Evk suggested a "moah reflection!" solution, which does indeed work. (See comments)
If there's a non-reflection approach, I'd be keen to know it though?
I tend to think that if you're this far down the rabbit hole (or, I suppose, through the looking glass), you should give up any pretence of benefitting from a static type system, and just take advantage of the dynamic runtime (assuming you're on .NET 4 or greater).
See https://blogs.msdn.microsoft.com/davidebb/2010/01/18/use-c-4-0-dynamic-to-drastically-simplify-your-private-reflection-code/ for an example of how much tidier the code can be (and a handy 'AsDynamic' extension method to make this easier).

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.

Get property value dynamically

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).

Categories

Resources