Advertisement
Guest User

Create Delegate recursive

a guest
Oct 28th, 2011
233
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 2.81 KB | None | 0 0
  1. public static TDelegate CreateDelegate<TDelegate>(
  2.     MethodInfo method,
  3.     object instance = null,
  4.     CreateOptions options = CreateOptions.None )
  5.     where TDelegate : class
  6. {
  7.     switch ( options )
  8.     {
  9.         case CreateOptions.None:
  10.             // Ordinary delegate creation, maintaining variance safety.
  11.             return Delegate.CreateDelegate( typeof( TDelegate ), instance, method ) as TDelegate;
  12.  
  13.         default:
  14.         {
  15.             MethodInfo delegateInfo = MethodInfoFromDelegateType( typeof( TDelegate ) );
  16.  
  17.             // Create delegate original and converted arguments.
  18.             var delegateTypes = delegateInfo.GetParameters().Select( d => d.ParameterType );
  19.             var methodTypes = method.GetParameters()
  20.                 .SkipWhile( p => p.ParameterType == typeof( Closure ) )
  21.                 .Select( p => p.ParameterType );
  22.             var delegateArgumentExpressions = CreateDelegateArgumentExpressions( delegateTypes, methodTypes );
  23.  
  24.             // Create method call.
  25.             List<Expression> arguments = new List<Expression>();
  26.             if ( method.GetParameters().FirstOrDefault().ParameterType == typeof( Closure ) )
  27.             {
  28.                 arguments.Add( Expression.Parameter( typeof( Closure ) ) );
  29.             }
  30.             arguments.AddRange( delegateArgumentExpressions.ConvertedArguments );
  31.             Expression methodCall = Expression.Call(
  32.                 instance == null ? null : Expression.Constant( instance ),
  33.                 method,
  34.                 arguments );
  35.  
  36.             // Convert return type when necessary.
  37.             Expression convertedMethodCall;
  38.             if ( delegateInfo.ReturnType == method.ReturnType )
  39.             {
  40.                 convertedMethodCall = methodCall;
  41.             }
  42.             else
  43.             {
  44.                 try
  45.                 {
  46.                     convertedMethodCall = Expression.Convert( methodCall, delegateInfo.ReturnType );
  47.                 }
  48.                 catch ( InvalidOperationException )
  49.                 {
  50.                     // Attempt recursive downcasting of the type arguments when it is a delegate. E.g. Func<Action<T>>
  51.                     if ( method.ReturnType.IsDelegate() && method.ReturnType.IsGenericType )
  52.                     {
  53.                         PropertyInfo methodProperty = method.ReturnType.GetProperty( MethodProperty, typeof( MethodInfo ) );
  54.                         MemberExpression getDelegateMethod = Expression.Property( methodCall, methodProperty );
  55.                         Func<MethodInfo, object, CreateOptions, TDelegate> createDelegateDelegate = CreateDelegate<TDelegate>;
  56.                         MethodInfo createDelegateMethod
  57.                             = createDelegateDelegate.Method.GetGenericMethodDefinition( delegateInfo.ReturnType );
  58.                         MethodCallExpression createDelegate = Expression.Call(
  59.                             createDelegateMethod,
  60.                             getDelegateMethod, Expression.Constant( null ), Expression.Constant( CreateOptions.Downcasting ) );
  61.                         convertedMethodCall = createDelegate;
  62.                     }
  63.                     else
  64.                     {
  65.                         throw new InvalidOperationException( "Can't downcast the return type to its desired type." );
  66.                     }
  67.                 }
  68.             }
  69.  
  70.             return Expression.Lambda<TDelegate>(
  71.                 convertedMethodCall,
  72.                 delegateArgumentExpressions.OriginalArguments
  73.                 ).Compile();
  74.         }
  75.     }
  76. }
  77.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement