Share via


Another attempt at Functions as objects.

One of the challenges in the Method class is that C# doesn’t let me apply generics as signatures all over the place. I would have liked to make the delegate type a type parameter, and somehow specify that Method.Invoke matched the signature of the delegate, etc. But it just can’t be done.

So Cyrus suggested I limited to just functions from A to B:

      delegate B Function<A, B> (A a);

I gave it a try but ran in to snag with methods that have no return type (‘void’) or no parameters (‘()’). The suggestion was to consider 2 more signatures:

      delegate A Creator();

      delegate void Action<A> (A a);

So, I created 3 classes, of for each type of signature.

Another thing I got stuck on was naming. I could have done:

      delegate B Function<A, B> (A a);

      class FunctionClass<A, B>

      {

            // ...

      }

Yuck on the name. Also got a lot of repetition of the type parameters throughout the class. So, I tried instead to move the delegate type into the class:

      class Function<A, B>

      {

            public delegate B Delegate(A a);

            // ...

      }

It seemed to be a bit cleaner.

I have a common base class for the 3 function types, but:

1. I don’t know what to call it, so I gave it the dumbest name I could think of.

2. I couldn’t push as much into the base as I would like. There’s still a lot of duplication here, but I’m limited by the rules of the language.

Enough blabber, here’s the code:

      class StartEndEvent : IDisposable

      {

            public event EventHandler OnStart;

            public event EventHandler OnEnd;

            object _sender;

            public IDisposable Open(object sender)

            {

                  this._sender = sender;

                  this.OnStart(_sender, null);

                  return (IDisposable)this;

            }

            void IDisposable.Dispose() { this.OnEnd(_sender, null); }

      }

      abstract class FunctionAbstractBase

      {

            // must be signed because 'Interlocked.Increment (ref uint)' doesn't exist.

            int _currentExecutingThreadCount = 0;

            public bool IsExecuting { get { return _currentExecutingThreadCount > 0; } }

            public StartEndEvent StartEndEvent = new StartEndEvent();

            protected FunctionAbstractBase()

            {

                  StartEndEvent.OnStart += delegate { System.Threading.Interlocked.Increment(ref this._currentExecutingThreadCount); };

                  StartEndEvent.OnEnd += delegate { System.Threading.Interlocked.Decrement(ref this._currentExecutingThreadCount); };

            }

      }

      class Function<A, B> : FunctionAbstractBase

      {

            public delegate B Delegate(A a);

            public readonly Delegate Value;

            public Function(Delegate function) : base() { this.Value = function; }

            public B Invoke(A value)

            {

                  using (this.StartEndEvent.Open(this))

                  {

                        return this.Value(value);

                  }

            }

            public static implicit operator Delegate(Function<A, B> m) { return m.Invoke; }

            public static implicit operator Function<A, B>(Delegate d) { return new Function<A, B>(d); }

      }

      class Action<A> : FunctionAbstractBase

      {

            public delegate void Delegate(A a);

            public readonly Delegate Value;

            public Action(Delegate function) : base() { this.Value = function; }

            public void Invoke(A value)

            {

                  using (this.StartEndEvent.Open(this))

                  {

                        this.Value(value);

                  }

            }

            public static implicit operator Delegate(Action<A> m) { return m.Invoke; }

            public static implicit operator Action<A>(Delegate d) { return new Action<A>(d); }

      }

      class Creator<A> : FunctionAbstractBase

      {

            public delegate A Delegate();

            public readonly Delegate Value;

            public Creator(Delegate function) : base() { this.Value = function; }

            public A Invoke()

            {

                  using (this.StartEndEvent.Open(this))

                  {

                        return this.Value();

                  }

            }

            public static implicit operator Delegate(Creator<A> m) { return m.Invoke; }

            public static implicit operator Creator<A>(Delegate d) { return new Creator<A>(d); }

      }

Which of course needs a sample of usage:

      // example usage

      class MyClass

      {

            // this is a verbose way of saying

            // void Method1(string)

            // {

            // //...

            // }

            //

            public readonly Action<string> Method1 = new Action<string>(delegate(string s)

            {

                  System.Console.WriteLine("Method1 was called - [{0}]", s);

            });

      }

      MyClass c = new MyClass();

      // the normal way to invoke

      c.Method1.Invoke("Method1.Invoke");

      // you can also pass c.Method1 around as a delegate

      Action<string>.Delegate f = c.Method1;

      f("via a delegate");

Comments