C# to Ruby - Proxies

July 5, 2014

Why?

I am learning Ruby, and one why I am doing so is with the Ruby Koans. Tonight I completed the Koan: “About Proxy Object Project.”

What is a proxy and why would you want to implement one? In its simplest form, a proxy is an interface or middleman to something else this could be anything: the file-system, the network or any other resource. A common use of a proxy is for intercepting calls and logging them. You can read more on Wikipedia.

How?

You need the class you want to proxy and the proxy class implementation that will intercept the calls do something and then invoke the desired method call. I would like to compare the C# implementation and the Ruby implementation.

Let’s start with the C# implementation. I got this from StackOverflow:

using System.Runtime.Remoting.Proxies.RealProxy;
namespace Proxy
{
	public class LoggingProxy<T> : RealProxy
	{
	    private readonly T _instance;

	    private LoggingProxy(T instance)
	        : base(typeof(T))
	    {
	        _instance = instance;
	    }

	    public static T Create(T instance)
	    {
	        return (T)new LoggingProxy<T>(instance).GetTransparentProxy();
	    }

	    public override IMessage Invoke(IMessage msg)
	    {
	        var methodCall = (IMethodCallMessage)msg;
	        var method = (MethodInfo)methodCall.MethodBase;

	        try
	        {
	            Console.WriteLine("Before invoke: " + method.Name);
	            var result = method.Invoke(_instance, methodCall.InArgs);
	            Console.WriteLine("After invoke: " + method.Name);
	            return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
	        }
	        catch (Exception e)
	        {
	            Console.WriteLine("Exception: " + e);
	            if (e is TargetInvocationException && e.InnerException != null)
	            {
	                return new ReturnMessage(e.InnerException, msg as IMethodCallMessage);
	            }

	            return new ReturnMessage(e, msg as IMethodCallMessage);
	        }
	    }
	}
}

Let us examine this code to understand what is going on. The first thing we see is we need to add a reference and using statement to System.Runtime.Remoting.Proxies.RealProxy in order to inherit from RealProxy. The LoggingProxy is generic which will give us type safety. The class is a Singleton since it has a private constructor and needs to be created using the Create factory method. Finally, there is the Invoke method that will get called whenever a method is called on our proxied class that will do some logging for us and has some exception handling to ensure we don’t fall over ourselves.

Now to use the proxy class all you would need to do is:

ICalculator calculator = LoggingProxy<ICalculator>.Create(new Calculator());
calculator.Add(1,2);

Pretty simple, right? Nothing spectacular, there is some casting going on to ensure we get our method, but in terms of complexity not quite hectic? Well maybe…are you ever going to remember this by heart?

Let’s contrast that with how the Rubyists do this sort of thing

class Proxy
	def initialize(target_object)
		@object = target_object
    end

    def method_missing(method_name, *args, &block)
    	begin
    		puts 'Before Invoke ' + method_name
    		@object.send(method_name, *args, &block)
    		puts 'After Invoke ' + method_name
    	rescue NameError => ex
    		puts 'Exception ' + ex.message
    	end
    end
end

Again let’s walk through this code. First thing is that Ruby is a dynamic language and therefore we don’t have a generic class that will ‘Strongly’ type our proxied class. We have initialize that takes an instance of our object that will be proxied, so there is no Create factory method. Also, no private constructor so this is not a singleton. We then extend the method_missing method do our logging in a begin rescue block and proxy off to our class the method that was called together with any args or blocks.

Now how would you use this?

calculator = Proxy.new(Calculator.new)
calculator.add(1, 2)

Wow, that is a quite a bit of typing. I much prefer the Ruby approach which saves a lot of keystrokes. I am not going to declare that one is better or superior to the other. Ruby and C# are two different languages with different strengths and weaknesses. But damn I know which I would rather want to use.

Conclusion

In conclusion, its pretty clear that C# takes a long winded approach to creating proxies, and this is not very obvious to implement. The Ruby approach whilst very concise doesn’t give you the security of type safety. Personally I would prefer to write the Ruby code as it is a lot more straightforward and much easier on the eyes.

I am going to try and do these comparisons regularly. If anything its a way for me to learn more about both languages


Discussion, links, and tweets

My name is Deon Heyns and I am a developer learning things and documenting them in realtime. Python, Ruby, Scala, .NET, and Groovy are all languages I have written code in. I appeared in the New York Post once. I host my code up at GitHub and Bitbucket so have a look at my code, fork it and send those pull requests.

comments powered by Disqus