Created
January 25, 2012 15:05
-
-
Save jcdickinson/1676672 to your computer and use it in GitHub Desktop.
Interface Delegate Methods/Mixins
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Program | |
| { | |
| static void Main(string[] args) | |
| { | |
| var ge = new GameEntity( | |
| me => | |
| { | |
| // WHOAH! We can store some private data for the mixin. | |
| // Starting to look like javascript though :(. | |
| var tt = 0f; | |
| return dt => Console.WriteLine("AI Total Time = {0}", tt += dt); | |
| }, | |
| me => | |
| { | |
| var tt = 0f; | |
| return dt => Console.WriteLine("Physics Total Time = {0}", tt += dt); | |
| } | |
| ); | |
| ge.AIRoutine(33); | |
| ge.PhysicsRoutine(33); | |
| ge.PhysicsRoutine(33); | |
| Console.ReadLine(); | |
| } | |
| } | |
| public delegate void TimedFunc(float dt); | |
| class GameEntity : IGameEntity | |
| { | |
| public TimedFunc AIRoutine | |
| { | |
| get; | |
| private set; | |
| } | |
| public TimedFunc PhysicsRoutine | |
| { | |
| get; | |
| private set; | |
| } | |
| public GameEntity(Func<IGameEntity, TimedFunc> ai, Func<IGameEntity, TimedFunc> physics) | |
| { | |
| AIRoutine = ai(this); | |
| PhysicsRoutine = physics(this); | |
| } | |
| } | |
| interface IGameEntity | |
| { | |
| TimedFunc AIRoutine { get; } | |
| TimedFunc PhysicsRoutine { get; } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Program | |
| { | |
| static void Main(string[] args) | |
| { | |
| var ge = new GameEntity( | |
| (t, dt) => Console.WriteLine("AI!"), | |
| (t, dt) => Console.WriteLine("Physics!") | |
| ); | |
| ge.AIRoutine(100); | |
| ge.PhysicsRoutine(200); | |
| Console.ReadLine(); | |
| } | |
| } | |
| public delegate void TimedFunc<TThis>(TThis thisObject, float dt); | |
| public delegate void TimedFunc(float dt); | |
| class GameEntity : IGameEntity | |
| { | |
| public TimedFunc AIRoutine | |
| { | |
| get; | |
| private set; | |
| } | |
| public TimedFunc PhysicsRoutine | |
| { | |
| get; | |
| private set; | |
| } | |
| public GameEntity(TimedFunc<IGameEntity> ai, TimedFunc<IGameEntity> physics) | |
| { | |
| AIRoutine = this.ProvideTo<IGameEntity, TimedFunc<IGameEntity>, TimedFunc>(ai); | |
| PhysicsRoutine = this.ProvideTo<IGameEntity, TimedFunc<IGameEntity>, TimedFunc>(physics); | |
| } | |
| } | |
| interface IGameEntity | |
| { | |
| TimedFunc AIRoutine { get; } | |
| TimedFunc PhysicsRoutine { get; } | |
| } | |
| static class ExpressionExtensions | |
| { | |
| public static TDelegateOut ProvideTo<TThis, TDelegateIn, TDelegateOut>(this TThis thisObject, TDelegateIn del) | |
| { | |
| if ((thisObject == null).OnlyIfDebug()) | |
| throw new ArgumentNullException("thisObject"); | |
| if ((del == null).OnlyIfDebug()) | |
| throw new ArgumentNullException("del"); | |
| var outType = typeof(TDelegateOut); | |
| var inType = typeof(TDelegateIn); | |
| var outInvoke = outType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); | |
| var inInvoke = inType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); | |
| // Check that both are delegates and that the return types match. | |
| if ((outInvoke == null || outInvoke.ReturnType != inInvoke.ReturnType).OnlyIfDebug()) | |
| throw new ArgumentOutOfRangeException("TDelegateOut"); | |
| if ((inInvoke == null).OnlyIfDebug()) | |
| throw new ArgumentOutOfRangeException("TDelegateIn"); | |
| var outParams = outInvoke.GetParameters(); | |
| var inParams = inInvoke.GetParameters(); | |
| // Check that the parameters make sense. | |
| if ((outParams.Length != inParams.Length - 1).OnlyIfDebug()) | |
| throw new ArgumentOutOfRangeException("TDelegateOut"); | |
| // Parameters for the return delegate. | |
| var paramsExprs = new ParameterExpression[outParams.Length]; | |
| // Arguments for the method call inside the expression. | |
| var args = new Expression[inParams.Length]; | |
| args[0] = Expression.Constant(thisObject); | |
| for (var i = 0; i < outParams.Length; i++) | |
| { | |
| var op = outParams[i]; | |
| var ip = inParams[i + 1]; | |
| if ((op.ParameterType != ip.ParameterType).OnlyIfDebug()) | |
| throw new ArgumentOutOfRangeException(string.Format("TDelegateOut({0})", op.Name)); | |
| paramsExprs[i] = Expression.Parameter(op.ParameterType, op.Name); | |
| args[i + 1] = paramsExprs[i]; | |
| } | |
| var call = Expression.Invoke(Expression.Constant(del), args); | |
| var lambda = Expression.Lambda<TDelegateOut>(call, paramsExprs); | |
| return lambda.Compile(); | |
| } | |
| private static bool OnlyIfDebug(this bool value) | |
| { | |
| #if DEBUG | |
| return value; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment