Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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");