Search code examples
c#proxyadapterdynamicobject

Proxying a collection interfaces dynamically


I have occasionally had cause to write collection class adapters, i.e. create an adapter for a class that implements IList<T> proxying its methods, whist adding some extra functionality. The IList interface has numerous methods / properties, I was wondering whether the straight-through proxy methods could be implemented dynamically? I had a look at DynamicObject, but could only find a few simple examples that proxy DTO classes, i.e. proxying a class that just has properties.

Is the proxying of IList<T> possible?

e.g.

public class ListProxy : IList<T>
{
  private IList<T> _adaptee;

  public ListProxy(IList<T> adaptee)
  {
    _adaptee = adaptee
  }

  // dynamically implement straight-through IList methods / properties
}

Solution

  • Something like this?

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Proxies;
    
    class Program
    {
        static void Main(string[] args)
        {
            IList<string> listProxy = MyProxyGenerator.Create<IList<string>>(new ListProxy<string>(new List<string>() { "aa","bb" }));
            bool b1 = listProxy.Contains("aa");
            bool b2 = listProxy.Contains("cc");
            int count = listProxy.Count;
            string s = listProxy[1];
        }
    
        public class ListProxy<T>
        {
            private IList<T> _adaptee;
    
            //Only method needed by proxy generator
            object Adaptee
            {
                get { return _adaptee; }
            }
    
            public ListProxy(IList<T> adaptee)
            {
                _adaptee = adaptee;
            }
        }
    
        class MyProxyGenerator : RealProxy
        {
            Type _Type;
            object _Instance;
    
            public static T Create<T>(object instance)
            {
                return (T)new MyProxyGenerator(typeof(T),instance).GetTransparentProxy();
            }
    
            MyProxyGenerator(Type type,object instance) : base(type)
            {
                _Type = type;
                _Instance = instance.GetType().InvokeMember("get_Adaptee", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, instance, null);
            }
    
            public override IMessage Invoke(IMessage msg)
            {
                IMethodCallMessage methodMessage = new MethodCallMessageWrapper((IMethodCallMessage)msg);
                string method = (string)msg.Properties["__MethodName"];
                object[] args = (object[])msg.Properties["__Args"];
    
                object retObj = _Instance.GetType().InvokeMember(method, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,null,_Instance,args);
                return new ReturnMessage(retObj,methodMessage.Args,methodMessage.ArgCount,methodMessage.LogicalCallContext,methodMessage);
            }
        }
    
    
    }