Reputation: 2138
I have an object obtained through a call to Type.GetProperty()
and I would like to know the combination of binding flags used to retrieve it.
When I inspect the object in the debugger, I can see it is a System.Reflection.RuntimePropertyInfo
with a BindingFlags
property containing the value I need. However, it seems that is an internal type because the compiler does not recognise it as a valid data type. Instead, it views the value returned by Type.GetProperty()
as a System.Reflection.PropertyInfo
which, funnily enough, does not contain a BindingFlags
property.
Can anybody suggest a reference I might add to the project in order for the compiler to understand the type System.Reflection.RuntimePropertyInfo
, or maybe an alternative way to obtain the BindingFlags
value? I suppose I could save the value I use in the call to Type.GetProperty()
and carry it along with the [Runtime]PropertyInfo
object wherever it goes, but that seems ugly.
I am (still!) using .NET framework 3.5, if that helps. Thanks!
EDIT:
The context of all this is a simple expression solver that gives my users access to a limited set of global objects and some of their properties, in order to create customised notifications with variable information coming from a database. At design time, my users define something like "Hello, [=Shipment.Recipient.Name]. Your order [=Shipment.Id] is ready for delivery."
and later on, when the notification is rendered, the system outputs "Hello, Bob. Your order 12345 is ready for delivery".
I considered using the CodeProvider
classes provided by the .NET Framework, but I need my code to run in a medium trust environment without Visual Studio installed, and I also do not want to expose too much functionality, because there is a possibility that third parties will have access to the notification designer, and I do not want anybody injecting any dangerous code in the notifications.
So, instead, I have written a simple expression parser/compiler/interpreter that provides the functionality I want to expose and no more; that is, property reading, string concatenation, basic arithmetic and date/time operations. The expressions are analysed for consistency, types are checked and a pseudo-assembler code is generated that can be serialised and stored as a sequence of bytes to be later recreated and executed upon a specific set of object instances, in order to yield the final expression result.
Parsing/compilation and execution happen in different contexts, at different times, with different sessions and maybe even on different machines, so I need to be able to recreate call chains from scratch as series of PropertyInfo objects from a base Type object obtained through its fully qualified name.
So far, I only examine BindingFlags.Public | BindingFlags.Instance
properties when I analyse call chains, but I see how I might, in the future, extend the implementation to include things like static properties, or whatever. I hence prefer not to assume any specific set of binding flags and I do not want to waste time discovering it during expression execution either, since I know its value at the time of compilation; I would rather store it in the serialised program so that I can pass it directly to Type.GetProperty()
when I reconstruct the call chain.
But the code where I serialise the compiled expression is definitely not in the same local scope as the code where I check whether some fragment of text entered by the user is a valid property in the current call chain, so by the time I need the value I have long ago forgotten the parameters passed to the Type.GetProperties()
function I called during analysis. That is how I find myself with a RuntimePropertyInfo
containing the value I want to store, but unable to reach it because the .NET compiler thinks it is an instance of its base class PropertyInfo
, that does not contain the BindingFlags
property. Very frustrating.
If I have to store the parameters used somewhere else, so that I can retrieve them during program serialization, then I will. But if I could simply cast the object to an instance of RuntimePropertyInfo
and read its BindingFlags
property, my life would be a little bit easier.
Upvotes: 2
Views: 2715
Reputation: 588
how about a hack like this:
PropertyInfo propinfo;
bool isinstance = Type.GetProperties(BindingFlags.Instance).Contains(propinfo);
bool ispublic = Type.GetProperties(BindingFlags.Public).Contains(propinfo);
Upvotes: 0
Reputation: 11753
var bindingFlags =
ReflectionUtil.GetPrivatePropertyValue<BindingFlags>(propertyInfo, "BindingFlags");
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml.Serialization;
using HQ.Util.General.DynamicProperties;
namespace HQ.Util.General.Reflection
{
public class ReflectionUtil
{
// ******************************************************************
public static BindingFlags BindingFlagsAll = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
public static BindingFlags BindingFlagsPublic = BindingFlags.Public | BindingFlags.Instance;
public static BindingFlags BindingFlagsAllButNotStatic = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
// ******************************************************************
/// <summary>
/// Will also set public property. Will set value in instance of any base class in hierarchy.
/// </summary>
/// <param name="obj"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void SetPrivatePropertyValue(object obj, string propertyName, object value)
{
PropertyInfo pi = GetPropertyInfoRecursive(obj.GetType(), propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (pi == null)
{
throw new ArgumentOutOfRangeException(propertyName, string.Format("Property {0} was not found in Type {1}", propertyName, obj.GetType().FullName));
}
pi.SetValue(obj, value);
}
// ******************************************************************
/// <summary>
/// Will also get public property. Will get value in instance of any base class in hierarchy.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public static T GetPrivatePropertyValue<T>(object obj, string propertyName)
{
PropertyInfo pi = GetPropertyInfoRecursive(obj.GetType(), propertyName);
if (pi == null)
{
throw new ArgumentOutOfRangeException(propertyName, string.Format("Property {0} was not found in Type {1}", propertyName, obj.GetType().FullName));
}
return (T)pi.GetValue(obj);
}
// ******************************************************************
/// <summary>
/// This is mainly used to look for private properties recursively because "FlattenHierarchy" is only applied on static members.
/// And also because private property could only be gotten for declared class type, not hierarchy.
/// </summary>
/// <param name="type"></param>
/// <param name="propertyName"></param>
/// <param name="bindingFlags"></param>
/// <returns></returns>
public static PropertyInfo GetPropertyInfoRecursive(Type type, string propertyName, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
{
PropertyInfo pi = type.GetProperty(propertyName, bindingFlags);
if (pi == null && type.BaseType != null)
{
pi = GetPropertyInfoRecursive(type.BaseType, propertyName, bindingFlags);
}
return pi;
}
Upvotes: 0