Carvo Loco
Carvo Loco

Reputation: 2138

Get BindingFlags from PropertyInfo

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

Answers (2)

Mightywill
Mightywill

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

Eric Ouellet
Eric Ouellet

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

Related Questions