Click here to Skip to main content
15,868,122 members
Articles / Programming Languages / C#

Dynamic Decorator and Castle DynamicProxy Comparison

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
1 Jul 2011CPOL3 min read 35K   199   8   13
Compare performance and features between Dynamic Decorator and Castle DynamicProxy

Introduction

Recently, I got a chance to play with Castle DynamicProxy a bit and did some comparisons between it and Dynamic Decorator. I found some interesting points and would like to share in this blog.

They are similar in that both use proxy concept. Both can be used to extend object functionality and add aspects to objects without modifying existing classes. The difference is that Dynamic Decorator overrides .NET's RealProxy and reuses its transparent proxy technology while Castle DynamicProxy uses a customized proxy technology. Your can find more information about them in the following links:

The CreateProxy method of the ObjectProxyFactory class in the Dynamic Decorator is mostly close to CreateInterfaceProxyWithTarget method of the ProxyGenerator class in the Castle DynamicProxy. The test is limited to use them to add some preprocessing functionality to an existing object.

Test Code

In this test, we try to add some logging functionality to an existing object. The following is the code for this test.

C#
public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.Write("Calling: " + invocation.Method.Name + "\n");
        invocation.Proceed();
    }
}

class Program
{
    static void Main(string[] args)
    {
        string path = Path.GetDirectoryName
		(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
        FileStream fileStream = null;
        if (!File.Exists(path + "\\hrlog.txt"))
        {
            fileStream = new FileStream(path + "\\hrlog.txt", FileMode.Create);
        }
        else
            fileStream = new FileStream(path + "\\hrlog.txt", FileMode.Truncate);

        TextWriter tmp = Console.Out;
        StreamWriter sw1 = new StreamWriter(fileStream);
        Console.SetOut(sw1);

        IEmployee emp = new Employee(1, "John", "Smith", new DateTime(1990, 4, 1), 1);
        IEmployee iemp = null;
        System.Int32? id = null;
        System.String detail = "";
        DateTime? dtStart = null;
        TimeSpan? ts = null;

        //Performance test for Castle DynamicProxy
        dtStart = DateTime.Now;
        for (int i = 0; i < 1000; i++)
        {
            ProxyGenerator generator = new ProxyGenerator();
            iemp = generator.CreateInterfaceProxyWithTarget<IEmployee>
					(emp, new LoggingInterceptor());

            id = iemp.EmployeeID;
            detail = iemp.DetailsByLevel(2);
        }
        ts = DateTime.Now - dtStart.Value;
        Console.Write("Using Castle CreateInterfaceProxyWithTarget: " + 
					ts.Value.ToString() + "\n");

        //Performance test for Dynamic Decorator
        dtStart = DateTime.Now;
        for (int i = 0; i < 1000; i++)
        {
            iemp = (IEmployee)ObjectProxyFactory.CreateProxy(
                emp,
                new String[] { "DetailsByLevel" },
                new Decoration((x, y) =>
                {
                    Console.Write("Calling: " + x.CallCtx.MethodName + "\n");
                }, null),
                null);

            id = iemp.DepartmentID;
            detail = iemp.DetailsByLevel(2);
        }
        ts = DateTime.Now - dtStart.Value;
        Console.Write("Using Dynamic Decorator: " + ts.Value.ToString() + "\n");

        //More features for Dynamic Decorator
        emp = (IEmployee)ObjectProxyFactory.CreateProxy(
            emp,
            new String[] { "DetailsByLevel" },
            new Decoration((x, y) =>
            {
                IMethodCallMessage method = x.CallCtx;
                string str = "Entering " + x.Target.GetType().ToString() + 
				"." + method.MethodName +
                    "(";
                int i = 0;
                foreach (object o in method.Args)
                {
                    if (i > 0)
                        str = str + ", ";
                    str = str + o.ToString();
                }
                str = str + ")";

                Console.WriteLine(str);
                Console.Out.Flush();
            }, null),
            null);

        id = emp.DepartmentID;
        detail = emp.DetailsByLevel(2);

        Console.SetOut(tmp);
        sw1.Close();
        fileStream.Close();
    }
}

Performance

The first part of the code compares Castle DynamicProxy's performance with Dynamic Decorator's. In the above code, an object emp of class Employee is created. The first loop simply calls CreateInterfaceProxyWithTarget method of the ProxyGenerator class of the Castle DynamicProxy to create a proxy, then, uses the proxy to call the methods of the object emp for 1000 times. The second loop simply calls CreateProxy method of the ObjectProxyFactory class of the Dynamic Decorator, then, uses the proxy to call the methods of the object emp for 1000 times. The execution time of each loop is presented in the following table.

Castle DynamicProxy - First LoopDynamic Decorator - Second Loop
00:01:13.497648000:00:00.0781225

The Dynamic Decorator is orders of magnitude faster than the Castle DynamicProxy for doing exactly the same thing. Actually, the execution time for Dynamic Decorator is negligible. The Dynamic Decorator is clearly a winner in terms of performance.

Features

The following paragraphs discuss the feature differences between Dynamic Decorator and Castle DynamicProxy.

With Castle DynamicProxy, the preprocessing functionality is added to all methods of the object. There is no easy way to specify a particular method to decorate. It is either all methods or no methods to get the additional functionality. With Dynamic Decorator, however, individual methods can be specified. For instance, in the above code, we specify only the method DetailsByLevel when calling ObjectProxyFactory.CreateProxy of the Dynamic Decorator.

With Dynamic Decorator, you can access the method call context from within additional functionality. For example, in the above code, we are able to get the value of the parameter of the method DetailsByLevel. I am not aware of a way to do it in the Castle DynamicProxy.

From the above code, you see the proxy of the Dynamic Decorator can be chained. The variable emp originally references to the target object. And later, it references to the proxy of the target. You can keep doing this to create a chain of proxies each time adding some extra functionality.

There are other features of Dynamic Decorator which can be used to enhance the preprocessing and postprocessing functionality. Please see the article Add Aspects to Object Using Dynamic Decorator for details.

The Dynamic Decorator has more features which can be used to enhance the preprocessing and postprocessing code.

Conclusion

The Dynamic Decorator is specifically designed to add additional functionality to objects. It is a lightweight and feature-rich tool to extend object functionality and to add aspects to objects. On the other hand, although the Castle DynamicProxy can be used to add aspects to objects, it suffers performance issue and has limited features to enhance the aspects.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Object-oriented (OO) is about "classes" not "objects". But I truly believe that "objects" deserve more our attentions. If you agree, read more on... Dynamic Object Programming (DOP), Component-Based Object Extender (CBO Extender), AOP Container and Dynamic Decorator Pattern.

Mobile development is not just another type of front end. The real challenge is actually in the back end: How to present meaningful information in time to mobile users with exponentially increased data flooding around? Here is my first mobile solution: SmartBars - Barcode Reader, Price Comparison and Coupons.

Gary lives in southeast Michigan. My first programming language is FORTRAN. For the last a few years, I have primarily focused on .NET technologies with Mobile Development as my newest interest.

Comments and Discussions

 
Questionbullshit Pin
EvilShrike1-Jul-11 6:45
EvilShrike1-Jul-11 6:45 
AnswerRe: bullshit Pin
Gary H Guo1-Jul-11 7:27
Gary H Guo1-Jul-11 7:27 
GeneralRe: bullsh*t Pin
EvilShrike1-Jul-11 7:43
EvilShrike1-Jul-11 7:43 
GeneralRe: bullsh*t Pin
EvilShrike1-Jul-11 7:50
EvilShrike1-Jul-11 7:50 
GeneralRe: bullsh*t Pin
Gary H Guo1-Jul-11 8:36
Gary H Guo1-Jul-11 8:36 
GeneralRe: bullsh*t Pin
EvilShrike1-Jul-11 9:20
EvilShrike1-Jul-11 9:20 
GeneralRe: bullsh*t Pin
Gary H Guo1-Jul-11 9:33
Gary H Guo1-Jul-11 9:33 
GeneralRe: bullsh*t Pin
EvilShrike1-Jul-11 9:39
EvilShrike1-Jul-11 9:39 
GeneralRe: bullsh*t Pin
Gary H Guo1-Jul-11 9:58
Gary H Guo1-Jul-11 9:58 
QuestionIn fact here is what I was doing, before I moved on Pin
Sacha Barber1-Jul-11 6:00
Sacha Barber1-Jul-11 6:00 
AnswerRe: In fact here is what I was doing, before I moved on Pin
Gary H Guo1-Jul-11 7:15
Gary H Guo1-Jul-11 7:15 
AnswerRe: In fact here is what I was doing, before I moved on Pin
Gary H Guo2-Sep-11 9:50
Gary H Guo2-Sep-11 9:50 
QuestionI like this and have been working on something quite similar using RealProxy [modified] Pin
Sacha Barber1-Jul-11 5:50
Sacha Barber1-Jul-11 5:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.