Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C#

Introducing the LinFu Framework, Part II: LinFu.DynamicObject – Adding Dynamic Language Features to Statically Typed Languages

Rate me:
Please Sign up or sign in to vote.
4.97/5 (50 votes)
12 Nov 2007LGPL316 min read 144.7K   882   67  
Using LinFu.DynamicObject to add mixins, duck typing and multiple dispatch to your favorite .NET languages
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace LinFu.Delegates
{
    public class Closure : IDeferredArgument 
    {
        private MulticastDelegate _target;
        private IInvoker _invoker = new DefaultInvoker();
        private readonly List<object> _suppliedArguments = new List<object>();
        public Closure()
        {

        }
        public Closure(CustomDelegate body, Type returnType, 
            Type[] parameterTypes, params object[] suppliedArguments)
        {
            MulticastDelegate targetDelegate = DelegateFactory.DefineDelegate(body, returnType, parameterTypes);
            _target = targetDelegate;

            if (suppliedArguments == null || suppliedArguments.Length == 0)
                return;

            _suppliedArguments.AddRange(suppliedArguments);
        }
        public Closure(MethodInfo staticMethod, 
            params object[] suppliedArguments) 
        {
            if (!staticMethod.IsStatic)
                throw new ArgumentException("The target method must be static and it cannot be an instance method",
                                            "staticMethod");

            MulticastDelegate target = DelegateFactory.DefineDelegate(null, staticMethod);
            _target = target;

            if (suppliedArguments == null || suppliedArguments.Length == 0)
                return;

            _suppliedArguments.AddRange(suppliedArguments);
        }

        public Closure(object instance, MethodInfo targetMethod, 
            params object[] suppliedArguments)
        {
            MulticastDelegate target = DelegateFactory.DefineDelegate(instance, targetMethod);
            _target = target;

            if (suppliedArguments == null || suppliedArguments.Length == 0)
                return;

            _suppliedArguments.AddRange(suppliedArguments);
        }
        public Closure(MulticastDelegate target)
        {
            _target = target;
        }
        public Closure(MulticastDelegate target, params object[] suppliedArguments)
        {
            _target = target;

            if (suppliedArguments == null || suppliedArguments.Length == 0)
                return;

            _suppliedArguments.AddRange(suppliedArguments);
        }
        public List<object> Arguments
        {
            get { return _suppliedArguments;  }   
        }
        public MulticastDelegate Target
        {
           get
           {
               return _target;
           }
           set
           {
               _target = value;
           }
        }

        public IInvoker Invoker
        {
            get { return _invoker; }
            set { _invoker = value; }
        }

        public object Invoke(params object[] args)
        {
            if (_target == null)
                throw new NotImplementedException();

            if (_invoker == null)
                throw new NotImplementedException();
           
            return _invoker.Invoke(_target.Target, _target.Method, _suppliedArguments, args);
        }
        
        #region IDeferredArgument Members

        public object Evaluate()
        {
            return Invoke();
        }

        #endregion

        public TDelegate AdaptTo<TDelegate>()
            where TDelegate : class
        {
            return AdaptTo(typeof (TDelegate)) as TDelegate;
        }
        public MulticastDelegate AdaptTo(Type delegateType)
        {
            if (!typeof(MulticastDelegate).IsAssignableFrom(delegateType))
                throw new ArgumentException("Generic parameter 'TDelegate' must be derived from MulticastDelegate");

            // Create a 'fake' delegate that redirects its
            // calls back to this closure
            CustomDelegate body = delegate(object[] args)
                                      {
                                          return Invoke(args);
                                      };

            
            MulticastDelegate result = DelegateFactory.DefineDelegate(delegateType, body);
            return result;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer (Senior) Readify
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions