简体   繁体   中英

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

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;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM