Exemplo n.º 1
0
        /// <summary>
        /// Creates a default allocator for the pooled type.
        /// </summary>
        /// <returns>The allocator that was created.</returns>
        protected static Func <T> CreateDefaultAllocator()
        {
            var ctor = typeof(T).GetConstructor(Type.EmptyTypes);

            if (ctor == null)
            {
                throw new InvalidOperationException(CoreStrings.MissingDefaultCtor.Format(typeof(T).FullName));
            }

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                return(Expression.Lambda <Func <T> >(Expression.New(typeof(T))).Compile());
            }
            else
            {
                return(() => (T)ctor.Invoke(null));
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Registers a default interpolator for the specified type.
        /// </summary>
        /// <typeparam name="T">The type for which to register a default interpolator.</typeparam>
        public void RegisterDefault <T>()
        {
            var interpolator = default(Interpolator <T>);

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                var interpolateMethod = typeof(T).GetMethod("Interpolate",
                                                            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(T), typeof(Single) }, null);
                if (interpolateMethod != null)
                {
                    var paramValueStart = Expression.Parameter(typeof(T), "valueStart");
                    var paramValueEnd   = Expression.Parameter(typeof(T), "valueEnd");
                    var paramFn         = Expression.Parameter(typeof(EasingFunction), "fn");
                    var paramT          = Expression.Parameter(typeof(Single), "t");

                    var expInvokeFn   = Expression.Invoke(Expression.Coalesce(paramFn, Expression.Constant(Easings.EaseInLinear)), paramT);
                    var expLambdaBody = Expression.Call(paramValueStart, interpolateMethod, paramValueEnd, expInvokeFn);

                    interpolator = Expression.Lambda <Interpolator <T> >(expLambdaBody, paramValueStart, paramValueEnd, paramFn, paramT).Compile();
                }
            }
            else
            {
                if (typeof(IInterpolatable <T>).IsAssignableFrom(typeof(T)))
                {
                    // Invoke through interface
                    interpolator = (valueStart, valueEnd, fn, t) =>
                                   ((IInterpolatable <T>)valueStart).Interpolate(valueEnd, (fn ?? Easings.EaseInLinear)(t));
                }
                else
                {
                    // Invoke through pattern
                    var interpolateMethod = typeof(T).GetMethod("Interpolate",
                                                                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(T), typeof(Single) }, null);
                    if (interpolateMethod != null)
                    {
                        interpolator = (valueStart, valueEnd, fn, t) =>
                                       (T)interpolateMethod.Invoke(valueStart, new Object[] { valueEnd, fn, t });
                    }
                }
            }

            Register(interpolator);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DataBindingGetterBuilder"/> class.
        /// </summary>
        /// <param name="expressionType">The type of the bound expression.</param>
        /// <param name="dataSourceType">The type of the data source to which the expression is being bound.</param>
        /// <param name="expression">The binding expression with which to bind the dependency property.</param>
        public DataBindingGetterBuilder(Type expressionType, Type dataSourceType, String expression)
            : base(dataSourceType)
        {
            this.delegateType = typeof(DataBindingGetter <>).MakeGenericType(expressionType);

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                CreateReturnTarget(expressionType);

                var path          = BindingExpressions.GetBindingMemberPathPart(expression);
                var pathParts     = path.Contains(".") ? path.Split('.') : null;
                var pathFinalPart = (pathParts == null) ? path : pathParts[pathParts.Length - 1];

                var current = AddDataSourceReference();

                if (pathParts != null)
                {
                    for (int i = 0; i < pathParts.Length - 1; i++)
                    {
                        current = AddSafeReference(expression, current, pathParts[i]);
                    }
                }
                current = AddSafeReference(expression, current, pathFinalPart);

                var result = Expression.Convert(current, expressionType);

                AddReturn(result);
                AddReturnLabel();

                var lambdaBody = Expression.Block(variables, expressions);
                var lambda     = Expression.Lambda(delegateType, lambdaBody, parameters);

                lambdaExpression = lambda;
            }
            else
            {
                var expParamDataSource = Expression.Parameter(typeof(Object), "dataSource");

                var implMethod = typeof(DataBindingGetterBuilder).GetMethod(nameof(ReflectionBasedImplementation),
                                                                            BindingFlags.NonPublic | BindingFlags.Static);

                var path          = BindingExpressions.GetBindingMemberPathPart(expression);
                var pathParts     = path.Contains(".") ? path.Split('.') : null;
                var pathFinalPart = (pathParts == null) ? path : pathParts[pathParts.Length - 1];

                var expDataSource     = (Expression)Expression.Convert(expParamDataSource, dataSourceType);
                var expDataSourceType = dataSourceType;

                var current = dataSourceType;
                if (pathParts != null)
                {
                    for (int i = 0; i < pathParts.Length - 1; i++)
                    {
                        expDataSourceType = BindingExpressions.GetMemberType(BindingExpressions.FindPropertyOrField(expDataSourceType, pathParts[i]));
                        expDataSource     = Expression.PropertyOrField(expDataSource, pathParts[i]);
                    }
                }

                var member = BindingExpressions.FindPropertyOrField(expDataSourceType, pathFinalPart);
                if (!BindingExpressions.CanReadMember(member))
                {
                    return;
                }

                var expImplMethodCall = Expression.Call(implMethod,
                                                        Expression.Constant(member),
                                                        Expression.Convert(expDataSource, typeof(Object)));

                lambdaExpression = Expression.Lambda(delegateType,
                                                     Expression.Convert(
                                                         Expression.Convert(expImplMethodCall, BindingExpressions.GetMemberType(member)),
                                                         expressionType), expParamDataSource);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates an invocation delegate for a routed event which uses the <see cref="RoutingStrategy.Bubble"/> routing strategy.
        /// </summary>
        /// <param name="evt">A <see cref="RoutedEvent"/> which identifies the routed event for which to create an invocation delegate.</param>
        /// <returns>The invocation delegate for the specified routed event.</returns>
        private static Delegate CreateInvocationDelegateForBubbleStrategy(RoutedEvent evt)
        {
            /* BUBBLE STRATEGY
             * For a given event delegate type TDelegate, we're constructing a method which basically looks like this:
             *
             * void fn(DependencyObject element, p1, p2, ..., pN, RoutedEventData data)
             * {
             *      var index = 0;
             *      var handler = default(RoutedEventHandlerMetadata);
             *      var current = element;
             *
             *      while (ShouldContinueBubbling(element, ref current))
             *      {
             *          index = 0;
             *          while (GetEventHandler(current, RoutedEventID, ref index, ref handler))
             *          {
             *              if (ShouldEventBeRaisedForElement(data, handler.HandledEventsToo))
             *              {
             *                  handler.Handler(current, p1, p2, ..., pN, data);
             *              }
             *          }
             *
             *          RoutedEventID.RaiseRaisedNotification(current, data);
             *      }
             *
             *      if (data.AutoRelease)
             *          data.Release();
             * }
             */

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                var evtInvoke = evt.DelegateType.GetMethod("Invoke");
                var evtParams = evtInvoke.GetParameters().ToArray();

                var expParams       = evtParams.Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToList();
                var expParamElement = expParams.First();
                var expParamData    = expParams.Last();

                var expParts = new List <Expression>();
                var expVars  = new List <ParameterExpression>();

                var varIndex = Expression.Variable(typeof(Int32), "index");
                expVars.Add(varIndex);

                var varHandler = Expression.Variable(typeof(RoutedEventHandlerMetadata), "handlers");
                expVars.Add(varHandler);

                var varCurrent = Expression.Variable(typeof(DependencyObject), "current");
                expVars.Add(varCurrent);

                var innerEventHandlerParams = new List <ParameterExpression>();
                innerEventHandlerParams.Add(varCurrent);
                innerEventHandlerParams.AddRange(expParams.Skip(1));

                var expWhileBubbleBreakOuter = Expression.Label();
                var expWhileBubbleBreakInner = Expression.Label();

                var expWhileBubble = Expression.Loop(
                    Expression.IfThenElse(
                        Expression.Call(miShouldContinueBubbling, expParamElement, varCurrent),
                        Expression.Block(
                            Expression.Assign(varIndex, Expression.Constant(0)),
                            Expression.Loop(
                                Expression.IfThenElse(
                                    Expression.Call(miGetEventHandler, varCurrent, Expression.Constant(evt), varIndex, varHandler),
                                    Expression.IfThen(
                                        Expression.Call(miShouldEventBeRaisedForElement, expParamData, Expression.Property(varHandler, "HandledEventsToo")),
                                        Expression.Invoke(Expression.Convert(Expression.Property(varHandler, "Handler"), evt.DelegateType), innerEventHandlerParams)
                                        ),
                                    Expression.Break(expWhileBubbleBreakInner)
                                    ),
                                expWhileBubbleBreakInner
                                ),
                            Expression.Call(Expression.Constant(evt), miRaiseRaisedNotification, varCurrent, expParamData)
                            ),
                        Expression.Break(expWhileBubbleBreakOuter)
                        ),
                    expWhileBubbleBreakOuter
                    );
                expParts.Add(expWhileBubble);

                expParts.Add(Expression.IfThen(Expression.IsTrue(Expression.Property(expParamData, nameof(RoutedEventData.AutoRelease))),
                                               Expression.Call(expParamData, nameof(RoutedEventData.Release), null)));

                return(Expression.Lambda(evt.DelegateType, Expression.Block(expVars, expParts), expParams).Compile());
            }
            else
            {
                return(CreateDelegateForReflectionBasedImplementation(evt, nameof(ReflectionBasedImplementationForBubbleStrategy)));
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Creates an invocation delegate for a routed event which uses the <see cref="RoutingStrategy.Tunnel"/> routing strategy.
        /// </summary>
        /// <param name="evt">A <see cref="RoutedEvent"/> which identifies the routed event for which to create an invocation delegate.</param>
        /// <returns>The invocation delegate for the specified routed event.</returns>
        private static Delegate CreateInvocationDelegateForTunnelStrategy(RoutedEvent evt)
        {
            /* TUNNEL STRATEGY
             * Basically the opposite of the bubble strategy; we start at the root of the tree and work down.
             * Note that ShouldContinueTunnelling() builds a stack representing the path to take on the first call.
             *
             * void fn(DependencyObject element, p1, p2, ..., pN, RoutedEventData data)
             * {
             *      var index    = 0;
             *      var current  = default(DependencyObject);
             *      var handlers = default(List<RoutedEventHandlerMetadata>);
             *      var stack    = default(Stack<DependencyObject>);
             *
             *      while (ShouldContinueTunnelling(element, ref current, ref stack))
             *      {
             *          index = 0;
             *          while (GetEventHandler(current, RoutedEventID, index, out handler))
             *          {
             *              if (ShouldEventBeRaisedForElement(data, handler.HandledEventsToo))
             *              {
             *                  handler.Handler(current, p1, p2, ..., pN, data);
             *              }
             *          }
             *
             *          RoutedEventID.RaiseRaisedNotification(current, data);
             *      }
             *
             *      ReleaseTunnellingStack(stack);
             *
             *      if (data.AutoRelease)
             *          data.Release();
             * }
             */

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                var evtInvoke = evt.DelegateType.GetMethod("Invoke");
                var evtParams = evtInvoke.GetParameters().ToArray();

                var expParams       = evtParams.Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToList();
                var expParamElement = expParams.First();
                var expParamData    = expParams.Last();

                var expParts = new List <Expression>();
                var expVars  = new List <ParameterExpression>();

                var varIndex = Expression.Variable(typeof(Int32), "index");
                expVars.Add(varIndex);

                var varHandler = Expression.Variable(typeof(RoutedEventHandlerMetadata), "handler");
                expVars.Add(varHandler);

                var varCurrent = Expression.Variable(typeof(DependencyObject), "current");
                expVars.Add(varCurrent);

                var varStack = Expression.Variable(typeof(Stack <DependencyObject>), "stack");
                expVars.Add(varStack);

                var innerEventHandlerParams = new List <ParameterExpression>();
                innerEventHandlerParams.Add(varCurrent);
                innerEventHandlerParams.AddRange(expParams.Skip(1));

                var expWhileTunnelBreakOuter = Expression.Label();
                var expWhileTunnelBreakInner = Expression.Label();

                var expWhileTunnel = Expression.Loop(
                    Expression.IfThenElse(
                        Expression.Call(miShouldContinueTunnelling, expParamElement, varCurrent, varStack),
                        Expression.Block(
                            Expression.Assign(varIndex, Expression.Constant(0)),
                            Expression.Loop(
                                Expression.IfThenElse(
                                    Expression.Call(miGetEventHandler, varCurrent, Expression.Constant(evt), varIndex, varHandler),
                                    Expression.IfThen(
                                        Expression.Call(miShouldEventBeRaisedForElement, expParamData, Expression.Property(varHandler, "HandledEventsToo")),
                                        Expression.Invoke(Expression.Convert(Expression.Property(varHandler, "Handler"), evt.DelegateType), innerEventHandlerParams)
                                        ),
                                    Expression.Break(expWhileTunnelBreakInner)
                                    ),
                                expWhileTunnelBreakInner
                                ),
                            Expression.Call(Expression.Constant(evt), miRaiseRaisedNotification, varCurrent, expParamData)
                            ),
                        Expression.Break(expWhileTunnelBreakOuter)
                        ),
                    expWhileTunnelBreakOuter
                    );
                expParts.Add(expWhileTunnel);

                expParts.Add(Expression.Call(miReleaseTunnellingStack, varStack));

                expParts.Add(Expression.IfThen(Expression.IsTrue(Expression.Property(expParamData, nameof(RoutedEventData.AutoRelease))),
                                               Expression.Call(expParamData, nameof(RoutedEventData.Release), null)));

                return(Expression.Lambda(evt.DelegateType, Expression.Block(expVars, expParts), expParams).Compile());
            }
            else
            {
                return(CreateDelegateForReflectionBasedImplementation(evt, nameof(ReflectionBasedImplementationForTunnelStrategy)));
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Creates an invocation delegate for a routed event which uses the <see cref="RoutingStrategy.Direct"/> routing strategy.
        /// </summary>
        /// <param name="evt">A <see cref="RoutedEvent"/> which identifies the routed event for which to create an invocation delegate.</param>
        /// <returns>The invocation delegate for the specified routed event.</returns>
        private static Delegate CreateInvocationDelegateForDirectStrategy(RoutedEvent evt)
        {
            /* DIRECT STRATEGY
             * The simplest strategy; the event is only invoked on the element that raised it.
             * Our invocation delegate looks something like this:
             *
             * void fn(DependencyObject element, p1, p2, ..., pN, RoutedEventData data)
             * {
             *      var index = 0;
             *      var handler = default(RoutedEventHandlerMetadata);
             *
             *      while (GetEventHandler(element, RoutedEventID, ref index, ref handler))
             *      {
             *          if (ShouldEventBeRaisedForElement(data, handler.HandledEventsToo))
             *          {
             *              handler.Handler(element, p1, p2, ..., pN, data);
             *          }
             *      }
             *
             *      RoutedEventID.RaiseRaisedNotification(element, data);
             *
             *      if (data.AutoRelease)
             *          data.Release();
             * }
             */

            if (UltravioletPlatformInfo.IsRuntimeCodeGenerationSupported())
            {
                var evtInvoke = evt.DelegateType.GetMethod("Invoke");
                var evtParams = evtInvoke.GetParameters().ToArray();

                var expParams       = evtParams.Select(x => Expression.Parameter(x.ParameterType, x.Name)).ToList();
                var expParamElement = expParams.First();
                var expParamData    = expParams.Last();

                var expParts = new List <Expression>();
                var expVars  = new List <ParameterExpression>();

                var varIndex = Expression.Variable(typeof(Int32), "index");
                expVars.Add(varIndex);

                var varHandler = Expression.Variable(typeof(RoutedEventHandlerMetadata), "handlers");
                expVars.Add(varHandler);

                var expInvokeBreak = Expression.Label();
                var expInvoke      = Expression.Loop(
                    Expression.IfThenElse(
                        Expression.Call(miGetEventHandler, expParamElement, Expression.Constant(evt), varIndex, varHandler),
                        Expression.IfThen(
                            Expression.Call(miShouldEventBeRaisedForElement, expParamData, Expression.Property(varHandler, "HandledEventsToo")),
                            Expression.Invoke(Expression.Convert(Expression.Property(varHandler, "Handler"), evt.DelegateType), expParams)
                            ),
                        Expression.Break(expInvokeBreak)
                        ),
                    expInvokeBreak
                    );
                expParts.Add(expInvoke);

                var expRaiseRaised = Expression.Call(Expression.Constant(evt), miRaiseRaisedNotification, expParamElement, expParamData);
                expParts.Add(expRaiseRaised);

                expParts.Add(Expression.IfThen(Expression.IsTrue(Expression.Property(expParamData, nameof(RoutedEventData.AutoRelease))),
                                               Expression.Call(expParamData, nameof(RoutedEventData.Release), null)));

                return(Expression.Lambda(evt.DelegateType, Expression.Block(expVars, expParts), expParams).Compile());
            }
            else
            {
                return(CreateDelegateForReflectionBasedImplementation(evt, nameof(ReflectionBasedImplementationForDirectStrategy)));
            }
        }