File: System\Activities\Expressions\New.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
 
namespace System.Activities.Expressions
{
    using System.Activities;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Reflection;
    using System.Runtime;
    using System.Runtime.Collections;
    using System.Windows.Markup;
    using System.Linq.Expressions;
    using System.Collections.Generic;
    using System.Activities.Validation;
using System.Threading;
 
    [SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotMatchKeywords,
        Justification = "Optimizing for XAML naming. VB imperative users will [] qualify (e.g. New [New])")]
    [SuppressMessage(FxCop.Category.Naming, FxCop.Rule.IdentifiersShouldNotHaveIncorrectSuffix,
        Justification = "Optimizing for XAML naming.")]
    [ContentProperty("Arguments")]
    public sealed class New<TResult> : CodeActivity<TResult> 
    {
        Collection<Argument> arguments;
        Func<object[], TResult> function;
        ConstructorInfo constructorInfo;
        static MruCache<ConstructorInfo, Func<object[], TResult>> funcCache = 
            new MruCache<ConstructorInfo, Func<object[], TResult>>(MethodCallExpressionHelper.FuncCacheCapacity);
        static ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
 
        [SuppressMessage(FxCop.Category.Naming, FxCop.Rule.PropertyNamesShouldNotMatchGetMethods,
            Justification = "Optimizing for XAML naming.")]
        public Collection<Argument> Arguments
        {
            get
            {
                if (this.arguments == null)
                {
                    this.arguments = new ValidatingCollection<Argument>
                    {
                        // disallow null values
                        OnAddValidationCallback = item =>
                        {
                            if (item == null)
                            {
                                throw FxTrace.Exception.ArgumentNull("item");
                            }
                        }
                    };
                }
                return this.arguments;
            }
        }
 
        protected override void CacheMetadata(CodeActivityMetadata metadata)
        {
            bool foundError = false;
            ConstructorInfo oldConstructorInfo = this.constructorInfo;
 
            // Loop through each argument, validate it, and if validation
            // passed expose it to the metadata
            Type[] types = new Type[this.Arguments.Count];
            for (int i = 0; i < this.Arguments.Count; i++)
            {
                Argument argument = this.Arguments[i];
                if (argument == null || argument.Expression == null)
                {
                    metadata.AddValidationError(SR.ArgumentRequired("Arguments", typeof(New<TResult>)));
                    foundError = true;
                }
                else
                {
                    RuntimeArgument runtimeArgument = new RuntimeArgument("Argument" + i, this.arguments[i].ArgumentType, this.arguments[i].Direction, true);
                    metadata.Bind(this.arguments[i], runtimeArgument);
                    metadata.AddArgument(runtimeArgument);
                    types[i] = this.Arguments[i].Direction == ArgumentDirection.In ? this.Arguments[i].ArgumentType : this.Arguments[i].ArgumentType.MakeByRefType();
                }
            }
 
            // If we didn't find any errors in the arguments then
            // we can look for an appropriate constructor.
            if (!foundError)
            {
                constructorInfo = typeof(TResult).GetConstructor(types);
                if (constructorInfo == null && (!typeof(TResult).IsValueType || types.Length > 0))
                {
                    metadata.AddValidationError(SR.ConstructorInfoNotFound(typeof(TResult).Name));
                }
                else if ((this.constructorInfo != oldConstructorInfo) || (this.function == null))
                {
                    this.function = MethodCallExpressionHelper.GetFunc<TResult>(metadata, constructorInfo, funcCache, locker);
                }
            }
        } 
 
        protected override TResult Execute(CodeActivityContext context)
        {
            object[] objects = new object[this.Arguments.Count];
            for (int i = 0; i < this.Arguments.Count; i++)
            {
                objects[i] = this.Arguments[i].Get(context);
            }
            TResult result = this.function(objects);
            
            for (int i = 0; i < this.Arguments.Count; i++)
            {
                Argument argument = this.Arguments[i];
                if (argument.Direction == ArgumentDirection.InOut || argument.Direction == ArgumentDirection.Out)
                {
                    argument.Set(context, objects[i]);
                }
            }
            return result;
        }
 
    }
}