Getypte Datenmodelle nur mit Interfaces und Dynamic Proxies

Thomas Darimont

Erfahrenes Mitglied
Hallo!

Hier mal ein Beispiel wie man mit Hilfe von DynamicProxies ganz einfach Interface-basierte getypte Datenmodelle zur Laufzeit erzeugen kann. (In dem Beispiel hält man das Datenmodell im Hintergrund in einem allgemeinen IDictionary<string,object>, mit dem man durch das Datenmodell-Interface, welches vom DynamicProxy umgesetzt wird, Typsicher zugreifen kann).
Ich verwende hierzu das DynamicProxy Framework des Castle-Projects ( http://www.castleproject.org/dynamicproxy/). Es wäre jedoch auch möglich mit standard .Net mitteln (Reflection.Emit) eigene DynamicProxy Implementierungen zu erzeugen oder man "mißbraucht" den Remtoing-RealProxy:
http://www.tutorials.de/forum/net-a...-dynamic-proxy-unter-net.html?highlight=Proxy



C#:
using System;
using System.Collections.Generic;
using System.Text;
using ProxyGenerator = Castle.DynamicProxy.ProxyGenerator;
using IInterceptor = Castle.DynamicProxy.IInterceptor;

namespace De.Tutorials.Training
{
    public class DataModelProxyFactoryExample
    {
        public static void Main(string[] args)
        {
            IDataModel dataModel = DataModelProxyFactory.CreateDataModelProxyFor<IDataModel>();
            dataModel.Data = "Hallo";
            dataModel.Value = 10;
            Console.WriteLine(dataModel.Data);
            Console.WriteLine(dataModel.Value);
        }
    }

/// <summary>
/// A simple DataModel Interface
/// </summary>
    public interface IDataModel
    {
        String Data
        {
            get;
            set;
        }

        int Value
        {
            get;
            set;
        }
    }

    /// <summary>
    /// A Generic DataModel Proxy Factory
    /// </summary>
    public class DataModelProxyFactory
    {
        public static TargetType CreateDataModelProxyFor<TargetType>()
        {
            ProxyGenerator proxyGenerator = new ProxyGenerator();
            return (TargetType)proxyGenerator.CreateProxy(typeof(TargetType), new DataModelWrapper(typeof(TargetType)), new object());
        }
    }

    /// <summary>
    /// A simple DataModel wrapper
    /// </summary>
    public class DataModelWrapper : IInterceptor
    {

        private IDictionary<string, object> dictionary;

        private Type wrappedType;

        public DataModelWrapper(Type wrappedType)
        {
            this.wrappedType = wrappedType;
            this.dictionary = new Dictionary<string, object>();
        }

        #region IInterceptor Members

        public object Intercept(Castle.DynamicProxy.IInvocation invocation, params object[] args)
        {
            if (this.wrappedType.Equals(invocation.Method.DeclaringType))
            {
                if (invocation.Method.Name.StartsWith("get_"))
                {
                    return dictionary[GetPropertyNameFor(invocation.Method.Name)];

                }
                else if (invocation.Method.Name.StartsWith("set_"))
                {
                    dictionary[GetPropertyNameFor(invocation.Method.Name)] = args[0];
                    return args[0];
                }
            }
            return null;
        }

        private string GetPropertyNameFor(string methodName)
        {
            return methodName.Substring(4);
        }

        #endregion
    }
}

Btw. in Java schaut das ganze dann so aus:
http://www.tutorials.de/forum/java/...typte-modelle-erzeugen.html?highlight=Getyped

Gruß Tom
 
Hallo!

kleiner Nachtrag, mit Generics klappts natürlich auch:
C#:
using System;
using System.Collections.Generic;
using System.Text;
using ProxyGenerator = Castle.DynamicProxy.ProxyGenerator;
using IInterceptor = Castle.DynamicProxy.IInterceptor;

namespace De.Tutorials.Training
{
    public class DataModelProxyFactoryExample
    {
        public static void Main(string[] args)
        {
            IDataModel dataModel = DataModelProxyFactory.CreateDataModelProxyFor<IDataModel>();
            dataModel.Data = "Hallo";
            dataModel.Value = 10;
            Console.WriteLine(dataModel.Data);
            Console.WriteLine(dataModel.Value);


            IGenericDataModel<string, IDataModel> genericDataModel = DataModelProxyFactory.CreateDataModelProxyFor<IGenericDataModel<string, IDataModel>>();
            genericDataModel.Data = "Bubu";
            genericDataModel.Value = dataModel;
            Console.WriteLine(genericDataModel.Data);
            Console.WriteLine(genericDataModel.Value.Data + " " + genericDataModel.Value.Value);
        }
    }

    /// <summary>
    /// A simple DataModel Interface
    /// </summary>
    public interface IDataModel
    {
        String Data
        {
            get;
            set;
        }

        int Value
        {
            get;
            set;
        }
    }

    /// <summary>
    /// A simple GenericDataModel Interface
    /// </summary>
    public interface IGenericDataModel<TData,TValue>
    {
        TData Data
        {
            get;
            set;
        }

        TValue Value
        {
            get;
            set;
        }
    }

    /// <summary>
    /// A Generic DataModel Proxy Factory
    /// </summary>
    public class DataModelProxyFactory
    {
        public static TargetType CreateDataModelProxyFor<TargetType>()
        {
            ProxyGenerator proxyGenerator = new ProxyGenerator();
            return (TargetType)proxyGenerator.CreateProxy(typeof(TargetType), new DataModelWrapper(typeof(TargetType)), new object());
        }
    }

    /// <summary>
    /// A simple DataModel wrapper
    /// </summary>
    public class DataModelWrapper : IInterceptor
    {

        private IDictionary<string, object> dictionary;

        private Type wrappedType;

        public DataModelWrapper(Type wrappedType)
        {
            this.wrappedType = wrappedType;
            this.dictionary = new Dictionary<string, object>();
        }

        #region IInterceptor Members

        public object Intercept(Castle.DynamicProxy.IInvocation invocation, params object[] args)
        {
            if (this.wrappedType.Equals(invocation.Method.DeclaringType))
            {
                if (invocation.Method.Name.StartsWith("get_"))
                {
                    return dictionary[GetPropertyNameFor(invocation.Method.Name)];

                }
                else if (invocation.Method.Name.StartsWith("set_"))
                {
                    dictionary[GetPropertyNameFor(invocation.Method.Name)] = args[0];
                    return args[0];
                }
            }
            return null;
        }

        private string GetPropertyNameFor(string methodName)
        {
            return methodName.Substring(4);
        }

        #endregion
    }
}

Gruß Tom
 
Zurück