Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
ReflectionParameterBinder.cs323 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Concurrent;5using System.Linq.Expressions;6using System.Management.Automation.Internal;7using System.Reflection;8 9using Microsoft.PowerShell.Commands;10 11namespace System.Management.Automation12{13    /// <summary>14    /// The parameter binder for real CLR objects that have properties and fields decorated with the parameter attributes.15    /// </summary>16    internal class ReflectionParameterBinder : ParameterBinderBase17    {18        #region ctor19 20        /// <summary>21        /// Constructs the parameter binder with the specified type metadata. The binder is only valid22        /// for a single instance of a bindable object and only for the duration of a command.23        /// </summary>24        /// <param name="target">25        /// The target object that the parameter values will be bound to.26        /// </param>27        /// <param name="command">28        /// An instance of the command so that attributes can access the context.29        /// </param>30        internal ReflectionParameterBinder(31            object target,32            Cmdlet command)33            : base(target, command.MyInvocation, command.Context, command)34        {35        }36 37        /// <summary>38        /// Constructs the parameter binder with the specified type metadata. The binder is only valid39        /// for a single instance of a bindable object and only for the duration of a command.40        /// </summary>41        /// <param name="target">42        /// The target object that the parameter values will be bound to.43        /// </param>44        /// <param name="command">45        /// An instance of the command so that attributes can access the context.46        /// </param>47        /// <param name="commandLineParameters">48        /// The dictionary to use to record the parameters set by this object...49        /// </param>50        internal ReflectionParameterBinder(51            object target,52            Cmdlet command,53            CommandLineParameters commandLineParameters)54            : base(target, command.MyInvocation, command.Context, command)55        {56            this.CommandLineParameters = commandLineParameters;57        }58 59        #endregion ctor60 61        #region internal members62 63        #region Parameter default values64 65        /// <summary>66        /// Gets the default value for the specified parameter.67        /// </summary>68        /// <param name="name">69        /// The name of the parameter to get the default value of.70        /// </param>71        /// <returns>72        /// The default value of the specified parameter.73        /// </returns>74        /// <exception cref="GetValueException">75        /// If the ETS call to get the property value throws an exception.76        /// </exception>77        internal override object GetDefaultParameterValue(string name)78        {79            try80            {81                return GetGetter(Target.GetType(), name)(Target);82            }83            catch (TargetInvocationException ex)84            {85                Exception inner = ex.InnerException ?? ex;86                throw new GetValueInvocationException("CatchFromBaseAdapterGetValueTI",87                    inner,88                    ExtendedTypeSystem.ExceptionWhenGetting,89                    name, inner.Message);90            }91            catch (GetValueException) { throw; }92            catch (Exception e)93            {94                throw new GetValueInvocationException("CatchFromBaseAdapterGetValue",95                    e,96                    ExtendedTypeSystem.ExceptionWhenGetting,97                    name, e.Message);98            }99        }100        #endregion Parameter default values101 102        #region Parameter binding103 104        /// <summary>105        /// Uses ETS to set the property specified by name to the value on106        /// the target bindable object.107        /// </summary>108        /// <param name="name">109        ///     The name of the parameter to bind the value to.110        /// </param>111        /// <param name="value">112        ///     The value to bind to the parameter. It should be assumed by113        ///     derived classes that the proper type coercion has already taken114        ///     place and that any prerequisite metadata has been satisfied.115        /// </param>116        /// <param name="parameterMetadata"></param>117        /// <exception cref="SetValueException">118        /// If the setter raises an exception.119        /// </exception>120        internal override void BindParameter(string name, object value, CompiledCommandParameter parameterMetadata)121        {122            Diagnostics.Assert(!string.IsNullOrEmpty(name), "caller to verify name parameter");123 124            try125            {126                var setter = parameterMetadata != null127                    ? (parameterMetadata.Setter ??= GetSetter(Target.GetType(), name))128                    : GetSetter(Target.GetType(), name);129                setter(Target, value);130            }131            catch (TargetInvocationException ex)132            {133                Exception inner = ex.InnerException ?? ex;134                throw new SetValueInvocationException("CatchFromBaseAdapterSetValueTI",135                    inner,136                    ExtendedTypeSystem.ExceptionWhenSetting,137                    name, inner.Message);138            }139            catch (SetValueException) { throw; }140            catch (Exception e)141            {142                throw new SetValueInvocationException("CatchFromBaseAdapterSetValue",143                    e,144                    ExtendedTypeSystem.ExceptionWhenSetting,145                    name, e.Message);146            }147        }148 149        #endregion Parameter binding150 151        #endregion Internal members152 153        #region Private members154 155        static ReflectionParameterBinder()156        {157            // Statically add delegates that we typically need on startup or every time we run PowerShell - this avoids the JIT158            s_getterMethods.TryAdd(Tuple.Create(typeof(OutDefaultCommand), "InputObject"), static o => ((OutDefaultCommand)o).InputObject);159            s_setterMethods.TryAdd(Tuple.Create(typeof(OutDefaultCommand), "InputObject"), static (o, v) => ((OutDefaultCommand)o).InputObject = (PSObject)v);160 161            s_getterMethods.TryAdd(Tuple.Create(typeof(OutLineOutputCommand), "InputObject"), static o => ((OutLineOutputCommand)o).InputObject);162            s_getterMethods.TryAdd(Tuple.Create(typeof(OutLineOutputCommand), "LineOutput"), static o => ((OutLineOutputCommand)o).LineOutput);163            s_setterMethods.TryAdd(Tuple.Create(typeof(OutLineOutputCommand), "InputObject"), static (o, v) => ((OutLineOutputCommand)o).InputObject = (PSObject)v);164            s_setterMethods.TryAdd(Tuple.Create(typeof(OutLineOutputCommand), "LineOutput"), static (o, v) => ((OutLineOutputCommand)o).LineOutput = v);165 166            s_getterMethods.TryAdd(Tuple.Create(typeof(FormatDefaultCommand), "InputObject"), static o => ((FormatDefaultCommand)o).InputObject);167            s_setterMethods.TryAdd(Tuple.Create(typeof(FormatDefaultCommand), "InputObject"), static (o, v) => ((FormatDefaultCommand)o).InputObject = (PSObject)v);168 169            s_setterMethods.TryAdd(Tuple.Create(typeof(SetStrictModeCommand), "Off"), static (o, v) => ((SetStrictModeCommand)o).Off = (SwitchParameter)v);170            s_setterMethods.TryAdd(Tuple.Create(typeof(SetStrictModeCommand), "Version"), static (o, v) => ((SetStrictModeCommand)o).Version = (Version)v);171 172            s_getterMethods.TryAdd(Tuple.Create(typeof(ForEachObjectCommand), "InputObject"), static o => ((ForEachObjectCommand)o).InputObject);173            s_setterMethods.TryAdd(Tuple.Create(typeof(ForEachObjectCommand), "InputObject"), static (o, v) => ((ForEachObjectCommand)o).InputObject = (PSObject)v);174            s_setterMethods.TryAdd(Tuple.Create(typeof(ForEachObjectCommand), "Process"), static (o, v) => ((ForEachObjectCommand)o).Process = (ScriptBlock[])v);175 176            s_getterMethods.TryAdd(Tuple.Create(typeof(WhereObjectCommand), "InputObject"), static o => ((WhereObjectCommand)o).InputObject);177            s_setterMethods.TryAdd(Tuple.Create(typeof(WhereObjectCommand), "InputObject"), static (o, v) => ((WhereObjectCommand)o).InputObject = (PSObject)v);178            s_setterMethods.TryAdd(Tuple.Create(typeof(WhereObjectCommand), "FilterScript"), static (o, v) => ((WhereObjectCommand)o).FilterScript = (ScriptBlock)v);179 180            s_setterMethods.TryAdd(Tuple.Create(typeof(ImportModuleCommand), "Name"), static (o, v) => ((ImportModuleCommand)o).Name = (string[])v);181            s_setterMethods.TryAdd(Tuple.Create(typeof(ImportModuleCommand), "ModuleInfo"), static (o, v) => ((ImportModuleCommand)o).ModuleInfo = (PSModuleInfo[])v);182            s_setterMethods.TryAdd(Tuple.Create(typeof(ImportModuleCommand), "Scope"), static (o, v) => ((ImportModuleCommand)o).Scope = (string)v);183            s_setterMethods.TryAdd(Tuple.Create(typeof(ImportModuleCommand), "PassThru"), static (o, v) => ((ImportModuleCommand)o).PassThru = (SwitchParameter)v);184 185            s_setterMethods.TryAdd(Tuple.Create(typeof(GetCommandCommand), "Name"), static (o, v) => ((GetCommandCommand)o).Name = (string[])v);186            s_setterMethods.TryAdd(Tuple.Create(typeof(GetCommandCommand), "Module"), static (o, v) => ((GetCommandCommand)o).Module = (string[])v);187 188            s_setterMethods.TryAdd(Tuple.Create(typeof(GetModuleCommand), "Name"), static (o, v) => ((GetModuleCommand)o).Name = (string[])v);189            s_setterMethods.TryAdd(Tuple.Create(typeof(GetModuleCommand), "ListAvailable"), static (o, v) => ((GetModuleCommand)o).ListAvailable = (SwitchParameter)v);190            s_setterMethods.TryAdd(Tuple.Create(typeof(GetModuleCommand), "FullyQualifiedName"), static (o, v) => ((GetModuleCommand)o).FullyQualifiedName = (ModuleSpecification[])v);191 192            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "ErrorAction"),193                (o, v) =>194                {195                    v ??= LanguagePrimitives.ThrowInvalidCastException(null, typeof(ActionPreference));196                    ((CommonParameters)o).ErrorAction = (ActionPreference)v;197                });198            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "WarningAction"),199                (o, v) =>200                {201                    v ??= LanguagePrimitives.ThrowInvalidCastException(null, typeof(ActionPreference));202                    ((CommonParameters)o).WarningAction = (ActionPreference)v;203                });204            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "InformationAction"),205                (o, v) =>206                {207                    v ??= LanguagePrimitives.ThrowInvalidCastException(null, typeof(ActionPreference));208                    ((CommonParameters)o).InformationAction = (ActionPreference)v;209                });210            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "ProgressAction"),211                (o, v) =>212                {213                    v ??= LanguagePrimitives.ThrowInvalidCastException(null, typeof(ActionPreference));214                    ((CommonParameters)o).ProgressAction = (ActionPreference)v;215                });216            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "Verbose"), static (o, v) => ((CommonParameters)o).Verbose = (SwitchParameter)v);217            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "Debug"), static (o, v) => ((CommonParameters)o).Debug = (SwitchParameter)v);218            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "ErrorVariable"), static (o, v) => ((CommonParameters)o).ErrorVariable = (string)v);219            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "WarningVariable"), static (o, v) => ((CommonParameters)o).WarningVariable = (string)v);220            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "InformationVariable"), static (o, v) => ((CommonParameters)o).InformationVariable = (string)v);221            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "OutVariable"), static (o, v) => ((CommonParameters)o).OutVariable = (string)v);222            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "OutBuffer"), static (o, v) => ((CommonParameters)o).OutBuffer = (int)v);223            s_setterMethods.TryAdd(Tuple.Create(typeof(CommonParameters), "PipelineVariable"), static (o, v) => ((CommonParameters)o).PipelineVariable = (string)v);224        }225 226        private static readonly ConcurrentDictionary<Tuple<Type, string>, Func<object, object>> s_getterMethods227            = new ConcurrentDictionary<Tuple<Type, string>, Func<object, object>>();228 229        private static readonly ConcurrentDictionary<Tuple<Type, string>, Action<object, object>> s_setterMethods =230            new ConcurrentDictionary<Tuple<Type, string>, Action<object, object>>();231 232        private static Func<object, object> GetGetter(Type type, string property)233        {234            return s_getterMethods.GetOrAdd(Tuple.Create(type, property),235                (Tuple<Type, string> _) =>236                {237                    var target = Expression.Parameter(typeof(object));238                    return Expression.Lambda<Func<object, object>>(239                        Expression.Convert(240                            GetPropertyOrFieldExpr(type, property, Expression.Convert(target, type)),241                            typeof(object)),242                        new[] { target }).Compile();243                });244        }245 246        private static Action<object, object> GetSetter(Type type, string property)247        {248            return s_setterMethods.GetOrAdd(Tuple.Create(type, property),249                _ =>250                {251                    var target = Expression.Parameter(typeof(object));252                    var value = Expression.Parameter(typeof(object));253                    var propertyExpr = GetPropertyOrFieldExpr(type, property, Expression.Convert(target, type));254 255                    Expression expr = Expression.Assign(propertyExpr, Expression.Convert(value, propertyExpr.Type));256                    if (propertyExpr.Type.IsValueType && Nullable.GetUnderlyingType(propertyExpr.Type) == null)257                    {258                        var throwInvalidCastExceptionExpr =259                            Expression.Call(Language.CachedReflectionInfo.LanguagePrimitives_ThrowInvalidCastException,260                                            Language.ExpressionCache.NullConstant,261                                            Expression.Constant(propertyExpr.Type, typeof(Type)));262 263                        // The return type of 'ThrowInvalidCastException' is System.Object, but the method actually always264                        // throws 'PSInvalidCastException' when it's executed. So converting 'throwInvalidCastExceptionExpr'265                        // to 'propertyExpr.Type' is fine, because the conversion will never be hit.266                        expr = Expression.Condition(Expression.Equal(value, Language.ExpressionCache.NullConstant),267                                                    Expression.Convert(throwInvalidCastExceptionExpr, propertyExpr.Type),268                                                    expr);269                    }270 271                    return Expression.Lambda<Action<object, object>>(expr, new[] { target, value }).Compile();272                });273        }274 275        private static Expression GetPropertyOrFieldExpr(Type type, string name, Expression target)276        {277            const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;278            try279            {280                var propertyInfo = type.GetProperty(name, bindingFlags);281                if (propertyInfo != null)282                    return Expression.Property(target, propertyInfo);283            }284            catch (AmbiguousMatchException)285            {286                // This is uncommon - in C#, there is "new" property that hides a base property.287                // To get the correct property, get all properties, and assume the first that matches288                // the name we want is the correct one.  This seems fragile, but the DotNetAdapter289                // does the same thing290                foreach (var propertyInfo in type.GetProperties(bindingFlags))291                {292                    if (propertyInfo.Name.Equals(name, StringComparison.Ordinal))293                    {294                        return Expression.Property(target, propertyInfo);295                    }296                }297            }298 299            try300            {301                var fieldInfo = type.GetField(name, bindingFlags);302                if (fieldInfo != null)303                    return Expression.Field(target, fieldInfo);304            }305            catch (AmbiguousMatchException)306            {307                foreach (var fieldInfo in type.GetFields(bindingFlags))308                {309                    if (fieldInfo.Name.Equals(name, StringComparison.Ordinal))310                    {311                        return Expression.Field(target, fieldInfo);312                    }313                }314            }315 316            Diagnostics.Assert(false, "Can't find property or field?");317            throw PSTraceSource.NewInvalidOperationException();318        }319 320        #endregion Private members321    }322}323