c#中的绑定/解绑定

本文关键字:绑定 | 更新日期: 2023-09-27 18:08:04

如何实现类似于jQuery的绑定/解绑定?

class MyDataType<T>
{
    private List<T> data;
    ...
    public void Add(T value)
    {
        data.Add(value);
    }
    ...
}
...
MyDataTypeObject.Bind("Add",()=>Console.WriteLine("OnAdd"));
...
MyDataTypeObject.UnBind("Add");
...

c#中的绑定/解绑定

您可以使用Castle DynamicProxy完成此操作。首先,创建包含Bind()Unbind()方法的抽象基类,以及保存调用的字典:

public abstract class BindableBase
{
    private readonly Dictionary<string, Action> m_boundMethods =
        new Dictionary<string, Action>();
    protected Dictionary<string, Action> BoundMethods
    {
        get { return m_boundMethods; }
    }
    public void Bind(string method, Action action)
    {
        if (!m_boundMethods.ContainsKey(method))
            m_boundMethods.Add(method, null);
        m_boundMethods[method] += action;
    }
    public void Unbind(string method, Action action)
    {
        if (m_boundMethods.ContainsKey(method))
        {
            m_boundMethods[method] -= action;
            if (m_boundMethods[method] == null)
                m_boundMethods.Remove(method);
        }
    }
}

然后创建实现BindableBase的具体类。您需要将任何想要拦截的方法设置为virtual:

public class Foo<T> : BindableBase
{
    private readonly List<T> m_data = new List<T>();
    public virtual void Add(T value)
    {
        m_data.Add(value);
    }
}

然后创建拦截器,拦截对任何虚方法的调用,并从字典中调用适当的委托:

class Interceptor : IInterceptor
{
    private static readonly PropertyInfo BoundMethodsProperty =
        typeof(BindableBase).GetProperty(
            "BoundMethods", BindingFlags.Instance | BindingFlags.NonPublic);
    public void Intercept(IInvocation invocation)
    {
        var boudMethods =
            (Dictionary<string, Action>)BoundMethodsProperty.GetValue(
                invocation.InvocationTarget, null);
        invocation.Proceed();
        string method = invocation.Method.Name;
        Action action;
        if (boudMethods.TryGetValue(method, out action))
            action();
    }
}

最后,这只是一个生成代理并使用它的问题:

var proxyGenerator = new ProxyGenerator();
Foo<int> foo = proxyGenerator.CreateClassProxy<Foo<int>>(new Interceptor());
foo.Bind("Add", LogAdd);
foo.Add(42);
foo.Unbind("Add", LogAdd);
foo.Add(43);

您可以模拟它,但只能使用Events的预定义方法。

class MyDataType<T>
{
    EventHandler<EventArgs> OnAdded;
    private RaiseOnAdded() 
    {
        var onAdded = OnAdded
        if(onAdded != null) 
        {
           onAdded(this, new EventArgs());
        } 
    }
    private List<T> data;
    ...
    public void Add(T value)
    {
        data.Add(value);
        RaiseOnAdded(); // <-- Add knows to call OnAdded(..) 
    }
    ...
}
var hander = (s, e)=>Console.WriteLine("OnAdd"));
MyDataTypeObject.OnAdded  += handler;
MyDataTypeObject.OnAdded  -= handler;