C#4 – Tạo proxy truy xuất các thành viên private (dynamic + reflection)

private-access-lock-keyKết hợp reflection và dynamic, ta có thể tạo một lớp proxy dùng để truy xuất được các thành viên private của một đối tượng. Lớp proxy này được tôi xây dựng để làm một giải pháp cho câu hỏi của bạn thanh trong bài giới thiệu về reflection.

Lớp PrivateAccessProxy:

using System;
using System.Dynamic;
using System.Reflection;

class PrivateAccessProxy : DynamicObject
{
    const BindingFlags BINDING_FLAG =  BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

    private Object _obj; // object which contains the private members you want to access
    private Type _type; // type of _obj

    public PrivateAccessProxy(Object obj)
    {
        this._obj = obj;
        this._type = obj.GetType();
    }
    /// <summary>
    /// Invoke method
    /// </summary>
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        MethodInfo method = this._type.GetMethod(binder.Name, BINDING_FLAG);
        if (method != null)
        {
            result = method.Invoke(this._obj, args);
            return true;
        }
        result = null;
        return false;
    }

    public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
    {
        result = this._obj = args[0].ToString();
        return true;
    }

    /// <summary>
    /// Get property or field
    /// </summary>
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        // get property
        PropertyInfo prop =  this._type.GetProperty(binder.Name, BINDING_FLAG);
        if (prop == null)
        {
            // get field
            FieldInfo field =  this._type.GetField(binder.Name, BINDING_FLAG);
            if (field == null)
            {
                result = null;
                return false;
            }
            result = field.GetValue(this._obj);

        }else
            result = prop.GetValue(this._obj, null);

        return true;
    }

    /// <summary>
    /// Set property or field
    /// </summary>
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        // get property
        PropertyInfo prop =  this._type.GetProperty(binder.Name, BINDING_FLAG);
        if (prop == null)
        {
            // get field
            FieldInfo field =  this._type.GetField(binder.Name, BINDING_FLAG);
            if (field == null)
            {
                return false;
            }
            field.SetValue(this._obj, value);

        }else
            prop.SetValue(this._obj, value, null);

        return true;
    }

}

Kiểm tra:

class Foo
{
    private int x = 100;
    private int Add(int y)
    {
        return x + y;
    }
}
class Program
    {
        static void Main(string[] args)
        {
            var foo = new Foo();
            dynamic bar = new PrivateAccessProxy(foo);
            Console.WriteLine(bar.x); // 100
            Console.WriteLine(bar.Add(50)); // 150
            Console.Read();

        }
    }

YinYangIt’s Blog

Advertisements

7 thoughts on “C#4 – Tạo proxy truy xuất các thành viên private (dynamic + reflection)

    • Cách viết này chính là proxy pattern. Về pattern thì bạn không cần vội vàng, cần phải có thời gian code dài mới có thể hiểu và ứng dụng được nhiều loại pattern. Còn đối với các loại pattern thông thường thì có thể bạn sử dụng hằng ngày mà không nhận ra.

      Phản hồi
      • Mình thì ko nghĩ lúc nào cũng phải theo các cấu trúc y hệt như vậy mới gọi là Proxy pattern. Việc áp dụng interface hay abstract class là một cách tổng quan và hợp lý dựa trên OOP. Tuy nhiên chả lẽ có OOP mới có design pattern? Mình nghĩ trong từng trường hợp cần vận dụng linh hoạt các khả năng của ngôn ngữ lập trình và nếu việc tạo interface là dư thừa (không liên quan và cần thiết) thì vẫn có thể coi là một pattern. Dù sao thì việc sử dụng pattern là rất phổ biến và tùy thuộc vào việc nó có được “đặt tên” hay không thôi.

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s