簡體   English   中英

從PropertyInfo獲取BindingFlags

[英]Get BindingFlags from PropertyInfo

我有一個通過調用Type.GetProperty()獲得的對象,並且我想知道用於檢索它的綁定標志的組合。

當我在調試器中檢查對象時,可以看到它是一個System.Reflection.RuntimePropertyInfo ,它的BindingFlags屬性包含我需要的值。 但是,這似乎是內部類型,因為編譯器無法將其識別為有效的數據類型。 而是將Type.GetProperty()返回的值視為System.Reflection.PropertyInfo ,它很有趣,它不包含BindingFlags屬性。

有人可以建議我添加到項目中的引用,以使編譯器理解System.Reflection.RuntimePropertyInfo類型,或者是獲取BindingFlags值的替代方法嗎? 我想我可以保存我在Type.GetProperty()調用中使用的值,並將其隨[Runtime]PropertyInfo對象一起隨身攜帶,但這看起來很難看。

我(仍然!)使用.NET Framework 3.5,如果有幫助的話。 謝謝!

編輯:

所有這些內容的上下文都是一個簡單的表達式求解器,它使我的用戶可以訪問一組有限的全局對象及其某些屬性,以便使用來自數據庫的可變信息來創建自定義的通知。 在設計時,我的用戶定義了類似"Hello, [=Shipment.Recipient.Name]. Your order [=Shipment.Id] is ready for delivery." 之后,當發出通知時,系統將輸出“您好,鮑勃。您的訂單12345已准備好交付”

我考慮使用.NET Framework提供的CodeProvider類,但是我需要我的代碼在未安裝Visual Studio的中等信任環境中運行,並且我也不想公開太多功能,因為第三方可能會將有權訪問通知設計器,並且我不希望任何人在通知中注入任何危險代碼。

因此,我寫了一個簡單的表達式解析器/編譯器/解釋器,它提供了我想公開的功能,僅此而已。 即屬性讀取,字符串連接,基本算術和日期/時間操作。 分析表達式的一致性,檢查類型,並生成偽匯編代碼,可以將該偽匯編代碼序列化並存儲為字節序列,以便稍后在一組特定的對象實例上重新創建和執行,以生成最終表達式結果。

解析/編譯和執行發生在不同的上下文中,在不同的時間,不同的會話,甚至可能在不同的機器上,因此我需要能夠從頭開始重新創建調用鏈,作為從通過其完全獲得的基礎Type對象中獲得的一系列PropertyInfo對象限定名稱。

到目前為止,我僅檢查BindingFlags.Public | BindingFlags.Instance 當我分析調用鏈時,使用BindingFlags.Public | BindingFlags.Instance屬性,但是我看到將來如何擴展實現以包括靜態屬性之類的東西。 因此,我不想假設任何特定的綁定標志集,並且我也不想浪費時間在表達式執行期間發現它,因為我知道在編譯時它的值。 我寧願將其存儲在序列化程序中,以便在重建調用鏈時可以將其直接傳遞給Type.GetProperty()

但是我對編譯后的表達式進行序列化的代碼肯定與我檢查用戶輸入的某些文本片段在當前調用鏈中是否為有效屬性的代碼不在同一本地范圍內,因此當我需要該值時我很早以前就忘記了傳遞給在分析過程中調用的Type.GetProperties()函數的參數。 這就是我如何使用包含要存儲的值的RuntimePropertyInfo查找自己的方法,但由於.NET編譯器認為該值是其基類PropertyInfo的實例而沒有包含BindingFlags屬性,因此無法獲取它。 非常沮喪。

如果必須將使用的參數存儲在其他地方,以便可以在程序序列化期間檢索它們,則可以。 但是,如果我可以將對象簡單地轉換為RuntimePropertyInfo的實例並讀取其BindingFlags屬性,那么我的生活會更輕松一些。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM