ArgumentFixer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / ArgumentFixer.cs / 1305376 / ArgumentFixer.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.Activities.Presentation 
{
    using System.Activities.Expressions; 
    using System.ServiceModel.Activities; 
    using System.Activities.Statements;
    using Microsoft.VisualBasic.Activities; 
    using System.Collections.Generic;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.Validation;
    using System.Linq; 
    using System.Activities.ExpressionParser;
    using System.Activities.Validation; 
    using System.Reflection; 
    using System.ComponentModel;
    using System.Runtime; 
    using System.Activities.Presentation.View;
using System.Linq.Expressions;

    //base of helper class to fix one argument for one activity 
    abstract class ActivityArgumentFixer
    { 
        public abstract Type ActivityType { get; } 
        public abstract bool NeedsToFix(Activity activity, ActivityWithResult expression, bool isLocation);
        public abstract void Fix(Activity activity, Argument newArgument); 
    }

    class ActivityArgumentFixer : ActivityArgumentFixer
        where TActivity : Activity 
    {
        Func argumentGetter; 
        Action argumentSetter; 

        public ActivityArgumentFixer(Func argumentGetter, Action argumentSetter) 
        {
            this.argumentGetter = argumentGetter;
            this.argumentSetter = argumentSetter;
        } 

        public override bool NeedsToFix(Activity activity, ActivityWithResult expression, bool isLocation) 
        { 
            TActivity concreteActivity = activity as TActivity;
            if (concreteActivity == null) 
            {
                return false;
            }
 
            Argument argument = this.argumentGetter(concreteActivity, isLocation);
            return argument != null && argument.Expression == expression; 
        } 

        public override void Fix(Activity activity, Argument newArgument) 
        {
            TActivity concreteActivity = activity as TActivity;
            if (concreteActivity == null)
            { 
                return;
            } 
 
            this.argumentSetter(concreteActivity, newArgument);
        } 

        public override Type ActivityType
        {
            get { return typeof(TActivity); } 
        }
    } 
 
    //utility class to fix up invalid arguments for activities after validation
    static class ArgumentFixer 
    {
        static Dictionary argumentFixers = new Dictionary();

        public static void RegisterArgumentFixer (ActivityArgumentFixer fixer) 
        {
            ArgumentFixer.argumentFixers[fixer.ActivityType] = fixer; 
        } 

        // 
        // In some of our activities, such as non generic Assign, exposes arguments with no type constraints.
        //
        // In that case, the designer has to infer the type based on user entered expressions.
        // But those expression's inferred type changes when its context changes. 
        // Such context includes (e.g. Namespaces, Variable definition, References ...)
        // 
        // To maintain data laziness of our designers (so as to minimize user perceived latency), we postpone to 
        // work of type re-inferencing until validation pass where we will need to walk the tree.
        // 
        // This method is used to update the argument objects (and the underlying expression objects as well)
        // due to new type inferencing requirements.
        //
        // This is NOT the long term solution. Doing type inference right is not a realistic goal for Dev10 at 
        // this stage now. This should be consider a patch so as to make a reasonable experience for Assign.
        // 
        public static void UpdateInvalidArgumentsIfNecessary(object sender, ValidationService.ErrorsMarkedEventArgs args) 
        {
            if (args.Reason != ValidationReason.ModelChange) 
            {
                return;
            }
 
            // Re-compile erroreous expressions to see if update is necessary
            Dictionary lvalueReplacements = 
                ComputeLocationExpressionReplacements( 
                    from error in args.Errors where IsVisualBasicReferenceForUntypedArgument(error.Source) select error,
                    args.Context); 
            Dictionary rvalueReplacements =
                ComputeValueExpressionReplacements(
                    from error in args.Errors where IsVisualBasicValueForUntypedArgument(error.Source) select error,
                    args.Context); 

            using (EditingScope editingScope = args.ModelTreeManager.CreateEditingScope(string.Empty)) 
            { 
                editingScope.SuppressUndo = true;
                //Assign has special requirement that Value has to have the same type as To, so we need to track all Assign activities whose To have been changed 
                Dictionary modifiedAssigns = new Dictionary();
                foreach (ActivityWithResult expressionToFix in lvalueReplacements.Keys)
                {
                    Type expectedType = lvalueReplacements[expressionToFix]; 
                    string expressionText = ExpressionHelper.GetExpressionString(expressionToFix);
                    if (expressionToFix.ResultType.GetGenericArguments()[0] != expectedType) 
                    { 
                        args.Handled = true;
                        Argument newArgument = ConstructNewArgument(true, expectedType, expressionText); 
                        ReplaceArgument(expressionToFix, newArgument, args.ModelTreeManager);
                    }
                    Assign modifiedAssign = ValidationService.GetParent(expressionToFix) as Assign;
                    if (modifiedAssign != null) 
                    {
                        modifiedAssigns.Add(modifiedAssign, expectedType); 
                    } 
                }
 
                foreach (ActivityWithResult expressionToFix in rvalueReplacements.Keys)
                {
                    Type expectedType = rvalueReplacements[expressionToFix];
                    string expressionText = ExpressionHelper.GetExpressionString(expressionToFix); 
                    // Here is where more type inferencing is happening.
                    // Depending on context, r-value might not take the type inferred from the compiler. 
                    // 
                    // A classic example will be Assign string value to Nothing. By default, VB compiler
                    // output object as the expected type which is not really what I want. 
                    //
                    Assign assignToFix = ValidationService.GetParent(expressionToFix) as Assign;
                    if (assignToFix != null)
                    { 
                        if (modifiedAssigns.ContainsKey(assignToFix))
                        { 
                            expectedType = modifiedAssigns[assignToFix]; 
                            modifiedAssigns.Remove(assignToFix);
                        } 
                        else if (assignToFix.To != null)
                        {
                            expectedType = assignToFix.To.ArgumentType;
                        } 
                    }
                    if (expressionToFix.ResultType != expectedType) 
                    { 
                        args.Handled = true;
                        Argument newArgument = ConstructNewArgument(false, expectedType, expressionText); 
                        ReplaceArgument(expressionToFix, newArgument, args.ModelTreeManager);
                    }
                }
                foreach (Assign otherAssign in modifiedAssigns.Keys) 
                {
                    if (otherAssign.Value != null) 
                    { 
                        ActivityWithResult offendingExpression = otherAssign.Value.Expression;
                        Type expectedType = modifiedAssigns[otherAssign]; 
                        if (offendingExpression.ResultType != expectedType)
                        {
                            string expressionText = ExpressionHelper.GetExpressionString(offendingExpression);
                            if (expressionText != null) 
                            {
                                args.Handled = true; 
                                Argument newArgument = ConstructNewArgument(false, expectedType, expressionText); 
                                ReplaceArgument(offendingExpression, newArgument, args.ModelTreeManager);
                            } 
                            // Since r-value of Assign could potentially be any other expression activities, but type inferencing will stop here.
                            // There is no way to update expression activities now.
                        }
                    } 
                }
                // The completion of this specific editing scope will NOT result in an UndoUnit. 
                // This is done so to avoid infinite loop of validation -> fixup -> validation -> ... 
                // This is also done to avoid undo -> fixup -> undo -> ...
                // See UndoEngine for details on how I skipped that. 
                editingScope.Complete();
            }
        }
 
        static Dictionary ComputeLocationExpressionReplacements(IEnumerable lvalueErrors, EditingContext context)
        { 
            Dictionary lvalueReplacements = new Dictionary(); 
            foreach (ValidationError lvalueError in lvalueErrors)
            { 
                ActivityWithResult offendingExpression = (ActivityWithResult)lvalueError.Source;
                Type returnType;
                SourceExpressionException compileError;
                VisualBasicSettings settings; 
                VisualBasicDesignerHelper.RecompileVisualBasicReference(
                    offendingExpression, 
                    out returnType, 
                    out compileError,
                    out settings); 
                if (compileError == null)
                {
                    lvalueReplacements.Add(offendingExpression, returnType);
                    if (settings != null) 
                    {
                        //merge with import designer 
                        foreach (VisualBasicImportReference reference in settings.ImportReferences) 
                        {
                            ImportDesigner.AddImport(reference.Import, context); 
                        }
                    }
                }
            } 
            return lvalueReplacements;
        } 
 
        static Dictionary ComputeValueExpressionReplacements(IEnumerable rvalueErrors, EditingContext context)
        { 
            Dictionary rvalueReplacements = new Dictionary();
            foreach (ValidationError rvalueError in rvalueErrors)
            {
                ActivityWithResult offendingExpression = (ActivityWithResult)rvalueError.Source; 
                Type returnType;
                SourceExpressionException compileError; 
                VisualBasicSettings settings; 
                VisualBasicDesignerHelper.RecompileVisualBasicValue(
                    offendingExpression, 
                    out returnType,
                    out compileError,
                    out settings);
                if (compileError == null) 
                {
                    rvalueReplacements.Add(offendingExpression, returnType); 
                    if (settings != null) 
                    {
                        //merge with import designer 
                        foreach (VisualBasicImportReference reference in settings.ImportReferences)
                        {
                            ImportDesigner.AddImport(reference.Import, context);
                        } 
                    }
                } 
            } 
            return rvalueReplacements;
        } 

        static void ReplaceArgument(ActivityWithResult expressionToReplace, Argument newArgument, ModelTreeManager modelTreeManager)
        {
            ModelItem expressionModelItem = modelTreeManager.GetModelItem(expressionToReplace); 
            if (expressionModelItem != null)
            { 
                ModelItem argumentModelItem = expressionModelItem.Parent; 
                ModelItem parentObject = argumentModelItem.Parent;
 
                if (argumentModelItem.Source != null)
                {
                    ModelProperty argumentProperty = parentObject.Properties[argumentModelItem.Source.Name];
                    Type argumentPropertyType = argumentProperty.PropertyType; 
                    if (argumentPropertyType == typeof(InArgument) || argumentPropertyType == typeof(OutArgument))
                    { 
                        ModelItem newArgumentModel = parentObject.Properties[argumentModelItem.Source.Name].SetValue(newArgument); 
                        //make sure argument.Expression is wrapped in ModelItem as well
                        ModelItem newExpressionModel = newArgumentModel.Properties["Expression"].Value; 
                    }
                }
            }
            else 
            {
                Activity parentActivity = ValidationService.GetParent(expressionToReplace); 
                ActivityArgumentFixer fixer; 
                if (ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer))
                { 
                    fixer.Fix(parentActivity, newArgument);
                }
            }
        } 

        static Argument ConstructNewArgument(bool isLocationExpression, Type expectedType, string expressionText) 
        { 
            Argument newArgument = null;
 
            if (isLocationExpression)
            {
                newArgument = (Argument)Activator.CreateInstance(typeof(OutArgument<>).MakeGenericType(expectedType));
            } 
            else
            { 
                newArgument = (Argument)Activator.CreateInstance(typeof(InArgument<>).MakeGenericType(expectedType)); 
            }
 

            ActivityWithResult newExpression = ExpressionHelper.CreateExpression(expectedType, expressionText, isLocationExpression, null);
            newArgument.Expression = newExpression;
            return newArgument; 
        }
 
        static bool IsGenericType(Type query, Type genericTypeDefintion) 
        {
            return query.IsGenericType && query.GetGenericTypeDefinition() == genericTypeDefintion; 
        }

        static bool IsVisualBasicReferenceForUntypedArgument(Activity expression)
        { 
            if (!IsGenericType(expression.GetType(), typeof(VisualBasicReference<>)))
            { 
                return false; 
            }
            //only VB expressions for untyped arguments need to be fixed up, 
            //however there is no way to tell which argument on expression belongs to so we only handle few activities
            //which are known to have untyped arguments now.
            Activity parentActivity = ValidationService.GetParent(expression);
            ActivityArgumentFixer fixer; 
            if (!ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer))
            { 
                return false; 
            }
            return fixer.NeedsToFix(parentActivity, expression as ActivityWithResult, true); 
        }

        static bool IsVisualBasicValueForUntypedArgument(Activity expression)
        { 
            if (!IsGenericType(expression.GetType(), typeof(VisualBasicValue<>)))
            { 
                return false; 
            }
            //only VB expressions for untyped arguments need to be fixed up, 
            //however there is no way to tell which argument on expression belongs to so we only handle few activities
            //which are known to have untyped arguments now.
            Activity parentActivity = ValidationService.GetParent(expression);
 
            ActivityArgumentFixer fixer;
            if (!ArgumentFixer.argumentFixers.TryGetValue(parentActivity.GetType(), out fixer)) 
            { 
                return false;
            } 
            return fixer.NeedsToFix(parentActivity, expression as ActivityWithResult, false);
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK