溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

在.NET平臺怎么使用ReflectionDynamicObject優(yōu)化反射

發(fā)布時(shí)間:2022-03-10 10:24:23 來源:億速云 閱讀:207 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“在.NET平臺怎么使用ReflectionDynamicObject優(yōu)化反射”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“在.NET平臺怎么使用ReflectionDynamicObject優(yōu)化反射”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。

基于封裝的原則,API 的設(shè)計(jì)者會將部分成員(屬性、字段、方法等)隱藏以保證健壯性。但總有需要直接訪問這些私有成員的情況。

為了訪問一個(gè)類型的私有成員,除了更改 API 設(shè)計(jì)還有就是使用反射技術(shù):

public class MyApi
{
	public MyApi()
	{
		_createdAt = DateTime.Now;
	}
	private DateTime _createdAt;
	public int ShowTimes { get; private set; }
	public void ShowCreateTime()
	{
		Console.WriteLine(_createdAt);
		ShowTimes++;
	}
}

void Main()
{
	var api = new MyApi();
	var field = api.GetType().GetField("_createdAt", BindingFlags.NonPublic | BindingFlags.Instance);
	var value = field.GetValue(api);
	Console.WriteLine(value);
}

這種寫法并不優(yōu)雅:

代碼冗長,編寫麻煩。實(shí)現(xiàn)比較繞,不太直觀。

筆者基于“動態(tài)類型技術(shù)”探索出了一種相對來說比較優(yōu)雅的方案用于美化上述代碼,并為其命名為 ReflectionDynamicObject :

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    Console.WriteLine(wrapper._createdAt);
}

除了支持獲取值,ReflectionDynamicObject 還支持賦值:

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    wrapper._createdAt = new DateTime(2022, 2, 2, 22, 22, 22);
    api.ShowCreateTime();
}

除了字段,當(dāng)然也支持對屬性的操作:

void Main()
{
    var api = new MyApi();
    dynamic wrapper = ReflectionDynamicObject.Wrap(api);
    wrapper.ShowTimes = 100;
    Console.WriteLine(wraper.ShowTimes);
}

在對屬性的支持上,ReflectionDynamicObject 使用了“快速反射”技術(shù),將取值和復(fù)制操作生成了委托以優(yōu)化性能。

ReflectionDynamicObject 的實(shí)現(xiàn)原理

ReflectionDynamicObject 派生自 DynamicObject ,其內(nèi)部通過反射技術(shù)獲取到所有的屬性和字段并對其 getter 和 setter 方法進(jìn)行存儲并通過 TryGetMember 和 TrySetMember 方法經(jīng)運(yùn)行時(shí)調(diào)用。

ReflectionDynamicObject 的源代碼

public sealed class ReflectionDynamicObject : DynamicObject
{
    private readonly object _instance;
    private readonly Accessor _accessor;
    private ReflectionDynamicObject(object instance)
    {
        _instance = instance ?? throw new ArgumentNullException(nameof(instance));
        _accessor = GetAccessor(instance.GetType());
    }
    public static ReflectionDynamicObject Wrap(Object value)
        if (value == null) throw new ArgumentNullException(nameof(value));
        return new ReflectionDynamicObject(value);

    public override bool TryGetMember(GetMemberBinder binder, out object result)
        if (_accessor.TryFindGetter(binder.Name, out var getter))
        {
            result = getter.Get(_instance);
            return true;
        }
        return base.TryGetMember(binder, out result);
    public override bool TrySetMember(SetMemberBinder binder, object value)
        if (_accessor.TryFindSetter(binder.Name, out var setter))
            setter.Set(_instance, value);
        return base.TrySetMember(binder, value);
    #region 快速反射
    private interface IGetter
        object Get(object instance);
    private interface ISetter
        void Set(object instance, object value);
    private class Getter : IGetter
        private FieldInfo _field;
        public Getter(FieldInfo field)
            _field = field ?? throw new ArgumentNullException(nameof(field));
        public object Get(object instance)
            return _field.GetValue(instance);
    private class Setter : ISetter
        public Setter(FieldInfo field)
        public void Set(object instance, object value)
            _field.SetValue(instance, value);
    private class Getter<T1, T2> : IGetter
        private readonly Func<T1, T2> _getter;
        public Getter(Func<T1, T2> getter)
            _getter = getter ?? throw new ArgumentNullException(nameof(getter));
            return _getter((T1)instance);
    private class Setter<T1, T2> : ISetter
        private readonly Action<T1, T2> _setter;
        public Setter(Action<T1, T2> setter)
            this._setter = setter ?? throw new ArgumentNullException(nameof(setter));
            this._setter.Invoke((T1)instance, (T2)value);
    private class Accessor
        public Accessor(Type type)
            this._type = type ?? throw new ArgumentNullException(nameof(_type));
            var getter = new SortedDictionary<string, IGetter>();
            var setter = new SortedDictionary<string, ISetter>();
            var fields = _type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            foreach (var field in fields)
            {
                getter[field.Name] = new Getter(field);
                setter[field.Name] = new Setter(field);
            }
            var props = _type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            foreach (var item in props)
                if (item.CanRead)
                {
                    var method = item.GetMethod;
                    var funcType = typeof(Func<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var func = method.CreateDelegate(funcType);
                    var getterType = typeof(Getter<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var get = (IGetter)Activator.CreateInstance(getterType, func);
                    getter[item.Name] = get;
                }
                if (item.CanWrite)
                    var method = item.SetMethod;
                    var actType = typeof(Action<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var act = method.CreateDelegate(actType);
                    var setterType = typeof(Setter<,>).MakeGenericType(item.DeclaringType, item.PropertyType);
                    var set = (ISetter)Activator.CreateInstance(setterType, act);
                    setter[item.Name] = set;
            _getters = getter;
            _setters = setter;
        private readonly Type _type;
        private readonly IReadOnlyDictionary<string, IGetter> _getters;
        private readonly IReadOnlyDictionary<string, ISetter> _setters;
        public bool TryFindGetter(string name, out IGetter getter) => _getters.TryGetValue(name, out getter);
        public bool TryFindSetter(string name, out ISetter setter) => _setters.TryGetValue(name, out setter);
    private static Dictionary<Type, Accessor> _accessors = new Dictionary<Type, Accessor>();
    private static object _accessorsLock = new object();
    private static Accessor GetAccessor(Type type)
        if (_accessors.TryGetValue(type, out var accessor)) return accessor;
        lock (_accessorsLock)
            if (_accessors.TryGetValue(type, out accessor)) return accessor;
            accessor = new Accessor(type);
            var temp = new Dictionary<Type, Accessor>(_accessors);
            temp[type] = new Accessor(type);
            _accessors = temp;
            return accessor;
    #endregion
}

ReflectionDynamicObject 的局限性

基于復(fù)雜度的考慮,ReflectionDynamicObject 并未添加對“方法”的支持。這也就意味著對方法的調(diào)用是缺失的。雖然動態(tài)行為讓程序擺脫了對字符串的依賴,但是該實(shí)現(xiàn)對“重構(gòu)”的支持仍然不友好。

哪里用到了 ReflectionDynamicObject ?

Liquid 主題引擎 是筆者根據(jù) Liquid 語言和 Shopify 主題機(jī)制并采用 Fluid 模板引擎實(shí)現(xiàn)的一套 HTML 主題引擎。該引擎允許最終用戶自由的修改自己的主題模板而不會對宿主造成影響。最終目標(biāo)是做到多語言、多主題、高擴(kuò)展性以及所見即所得。

讀到這里,這篇“在.NET平臺怎么使用ReflectionDynamicObject優(yōu)化反射”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點(diǎn)還需要大家自己動手實(shí)踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI