MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Concurrent;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.ComponentModel;8using System.Data;9using System.Diagnostics;10using System.Diagnostics.CodeAnalysis;11using System.Dynamic;12using System.Globalization;13using System.Linq;14using System.Linq.Expressions;15using System.Management.Automation.Language;16using System.Management.Automation.Runspaces;17using System.Reflection;18using System.Reflection.Emit;19using System.Text;20using System.Threading;21using System.Xml;22 23using System.Management.Automation.Internal;24using Microsoft.PowerShell;25using Dbg = System.Management.Automation.Diagnostics;26 27#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings28 29namespace System.Management.Automation30{31 /// <summary>32 /// Base class for all Adapters33 /// This is the place to look every time you create a new Adapter. Consider if you34 /// should implement each of the virtual methods here.35 /// The base class deals with errors and performs additional operations before and after36 /// calling the derived virtual methods.37 /// </summary>38 internal abstract class Adapter39 {40 /// <summary>41 /// Tracer for this and derivative classes.42 /// </summary>43 [TraceSource("ETS", "Extended Type System")]44 protected static PSTraceSource tracer = PSTraceSource.GetTracer("ETS", "Extended Type System");45 #region virtual46 47 #region member48 49 internal virtual bool CanSiteBinderOptimize(MemberTypes typeToOperateOn) { return false; }50 51 protected static IEnumerable<string> GetDotNetTypeNameHierarchy(Type type)52 {53 for (; type != null; type = type.BaseType)54 {55 yield return type.FullName;56 }57 }58 59 protected static IEnumerable<string> GetDotNetTypeNameHierarchy(object obj)60 {61 return GetDotNetTypeNameHierarchy(obj.GetType());62 }63 64 /// <summary>65 /// Returns the TypeNameHierarchy out of an object.66 /// </summary>67 /// <param name="obj">Object to get the TypeNameHierarchy from.</param>68 protected virtual IEnumerable<string> GetTypeNameHierarchy(object obj)69 {70 return GetDotNetTypeNameHierarchy(obj);71 }72 73 /// <summary>74 /// Returns the cached typename, if it can be cached, otherwise constructs a new typename.75 /// By default, we don't return interned values, adapters can override if they choose.76 /// </summary>77 /// <param name="obj">Object to get the TypeNameHierarchy from.</param>78 protected virtual ConsolidatedString GetInternedTypeNameHierarchy(object obj)79 {80 return new ConsolidatedString(GetTypeNameHierarchy(obj));81 }82 83 /// <summary>84 /// Returns null if memberName is not a member in the adapter or85 /// the corresponding PSMemberInfo.86 /// </summary>87 /// <param name="obj">Object to retrieve the PSMemberInfo from.</param>88 /// <param name="memberName">Name of the member to be retrieved.</param>89 /// <returns>The PSMemberInfo corresponding to memberName from obj.</returns>90 protected abstract T GetMember<T>(object obj, string memberName) where T : PSMemberInfo;91 92 /// <summary>93 /// Returns the first PSMemberInfo whose name matches the specified <see cref="MemberNamePredicate"/>.94 /// Otherwise, return null.95 /// </summary>96 /// <param name="obj">Object to retrieve the PSMemberInfo from.</param>97 /// <param name="predicate">The predicate to find the matching member.</param>98 /// <returns>The PSMemberInfo corresponding to the predicate match.</returns>99 protected abstract T GetFirstMemberOrDefault<T>(object obj, MemberNamePredicate predicate) where T : PSMemberInfo;100 101 /// <summary>102 /// Retrieves all the members available in the object.103 /// The adapter implementation is encouraged to cache all properties/methods available104 /// in the first call to GetMember and GetMembers so that subsequent105 /// calls can use the cache.106 /// In the case of the .NET adapter that would be a cache from the .NET type to107 /// the public properties and fields available in that type.108 /// In the case of the DirectoryEntry adapter, this could be a cache of the objectClass109 /// to the properties available in it.110 /// </summary>111 /// <param name="obj">Object to get all the member information from.</param>112 /// <returns>All members in obj.</returns>113 protected abstract PSMemberInfoInternalCollection<T> GetMembers<T>(object obj) where T : PSMemberInfo;114 115 #endregion member116 117 #region property118 119 /// <summary>120 /// Returns the value from a property coming from a previous call to GetMember.121 /// </summary>122 /// <param name="property">PSProperty coming from a previous call to GetMember.</param>123 /// <returns>The value of the property.</returns>124 protected abstract object PropertyGet(PSProperty property);125 126 /// <summary>127 /// Sets the value of a property coming from a previous call to GetMember.128 /// </summary>129 /// <param name="property">PSProperty coming from a previous call to GetMember.</param>130 /// <param name="setValue">Value to set the property with.</param>131 /// <param name="convertIfPossible">Instructs the adapter to convert before setting, if the adapter supports conversion.</param>132 protected abstract void PropertySet(PSProperty property, object setValue, bool convertIfPossible);133 134 /// <summary>135 /// Returns true if the property is settable.136 /// </summary>137 /// <param name="property">Property to check.</param>138 /// <returns>True if the property is settable.</returns>139 protected abstract bool PropertyIsSettable(PSProperty property);140 141 /// <summary>142 /// Returns true if the property is gettable.143 /// </summary>144 /// <param name="property">Property to check.</param>145 /// <returns>True if the property is gettable.</returns>146 protected abstract bool PropertyIsGettable(PSProperty property);147 148 /// <summary>149 /// Returns the name of the type corresponding to the property's value.150 /// </summary>151 /// <param name="property">PSProperty obtained in a previous GetMember.</param>152 /// <param name="forDisplay">True if the result is for display purposes only.</param>153 /// <returns>The name of the type corresponding to the member.</returns>154 protected abstract string PropertyType(PSProperty property, bool forDisplay);155 156 /// <summary>157 /// Returns the string representation of the property in the object.158 /// </summary>159 /// <param name="property">Property obtained in a previous GetMember.</param>160 /// <returns>The string representation of the property in the object.</returns>161 protected abstract string PropertyToString(PSProperty property);162 163 /// <summary>164 /// Returns an array with the property attributes.165 /// </summary>166 /// <param name="property">Property we want the attributes from.</param>167 /// <returns>An array with the property attributes.</returns>168 protected abstract AttributeCollection PropertyAttributes(PSProperty property);169 170 #endregion property171 172 #region method173 174 /// <summary>175 /// Called after a non null return from GetMember to try to call176 /// the method with the arguments.177 /// </summary>178 /// <param name="method">The non empty return from GetMethods.</param>179 /// <param name="invocationConstraints">Invocation constraints.</param>180 /// <param name="arguments">The arguments to use.</param>181 /// <returns>The return value for the method.</returns>182 protected virtual object MethodInvoke(PSMethod method, PSMethodInvocationConstraints invocationConstraints, object[] arguments)183 {184 return this.MethodInvoke(method, arguments);185 }186 187 /// <summary>188 /// Called after a non null return from GetMember to try to call189 /// the method with the arguments.190 /// </summary>191 /// <param name="method">The non empty return from GetMethods.</param>192 /// <param name="arguments">The arguments to use.</param>193 /// <returns>The return value for the method.</returns>194 protected abstract object MethodInvoke(PSMethod method, object[] arguments);195 196 /// <summary>197 /// Called after a non null return from GetMember to return the overloads.198 /// </summary>199 /// <param name="method">The return of GetMember.</param>200 /// <returns></returns>201 protected abstract Collection<string> MethodDefinitions(PSMethod method);202 203 /// <summary>204 /// Returns the string representation of the method in the object.205 /// </summary>206 /// <returns>The string representation of the method in the object.</returns>207 protected virtual string MethodToString(PSMethod method)208 {209 StringBuilder returnValue = new StringBuilder();210 Collection<string> definitions = MethodDefinitions(method);211 for (int i = 0; i < definitions.Count; i++)212 {213 returnValue.Append(definitions[i]);214 returnValue.Append(", ");215 }216 217 returnValue.Remove(returnValue.Length - 2, 2);218 return returnValue.ToString();219 }220 221 #endregion method222 223 #region parameterized property224 225 /// <summary>226 /// Returns the name of the type corresponding to the property's value.227 /// </summary>228 /// <param name="property">Property obtained in a previous GetMember.</param>229 /// <returns>The name of the type corresponding to the member.</returns>230 /// <remarks>231 /// It is not necessary for derived methods to override this.232 /// This method is called only if ParameterizedProperties are present.233 /// </remarks>234 protected virtual string ParameterizedPropertyType(PSParameterizedProperty property)235 {236 Diagnostics.Assert(false, "adapter is not called for parameterized properties");237 throw PSTraceSource.NewNotSupportedException();238 }239 240 /// <summary>241 /// Returns true if the property is settable.242 /// </summary>243 /// <param name="property">Property to check.</param>244 /// <returns>True if the property is settable.</returns>245 /// <remarks>246 /// It is not necessary for derived methods to override this.247 /// This method is called only if ParameterizedProperties are present.248 /// </remarks>249 protected virtual bool ParameterizedPropertyIsSettable(PSParameterizedProperty property)250 {251 Diagnostics.Assert(false, "adapter is not called for parameterized properties");252 throw PSTraceSource.NewNotSupportedException();253 }254 255 /// <summary>256 /// Returns true if the property is gettable.257 /// </summary>258 /// <param name="property">Property to check.</param>259 /// <returns>True if the property is gettable.</returns>260 /// <remarks>261 /// It is not necessary for derived methods to override this.262 /// This method is called only if ParameterizedProperties are present.263 /// </remarks>264 protected virtual bool ParameterizedPropertyIsGettable(PSParameterizedProperty property)265 {266 Diagnostics.Assert(false, "adapter is not called for parameterized properties");267 throw PSTraceSource.NewNotSupportedException();268 }269 270 /// <summary>271 /// Called after a non null return from GetMember to return the overloads.272 /// </summary>273 /// <param name="property">The return of GetMember.</param>274 /// <remarks>275 /// It is not necessary for derived methods to override this.276 /// This method is called only if ParameterizedProperties are present.277 /// </remarks>278 protected virtual Collection<string> ParameterizedPropertyDefinitions(PSParameterizedProperty property)279 {280 Diagnostics.Assert(false, "adapter is not called for parameterized properties");281 throw PSTraceSource.NewNotSupportedException();282 }283 284 /// <summary>285 /// Called after a non null return from GetMember to get the property value.286 /// </summary>287 /// <param name="property">The non empty return from GetMember.</param>288 /// <param name="arguments">The arguments to use.</param>289 /// <returns>The return value for the property.</returns>290 /// <remarks>291 /// It is not necessary for derived methods to override this.292 /// This method is called only if ParameterizedProperties are present.293 /// </remarks>294 protected virtual object ParameterizedPropertyGet(PSParameterizedProperty property, object[] arguments)295 {296 Diagnostics.Assert(false, "adapter is not called for parameterized properties");297 throw PSTraceSource.NewNotSupportedException();298 }299 300 /// <summary>301 /// Called after a non null return from GetMember to set the property value.302 /// </summary>303 /// <param name="property">The non empty return from GetMember.</param>304 /// <param name="setValue">The value to set property with.</param>305 /// <param name="arguments">The arguments to use.</param>306 /// <remarks>307 /// It is not necessary for derived methods to override this.308 /// This method is called only if ParameterizedProperties are present.309 /// </remarks>310 protected virtual void ParameterizedPropertySet(PSParameterizedProperty property, object setValue, object[] arguments)311 {312 Diagnostics.Assert(false, "adapter is not called for parameterized properties");313 throw PSTraceSource.NewNotSupportedException();314 }315 316 /// <summary>317 /// Returns the string representation of the property in the object.318 /// </summary>319 /// <param name="property">Property obtained in a previous GetMember.</param>320 /// <returns>The string representation of the property in the object.</returns>321 /// <remarks>322 /// It is not necessary for derived methods to override this.323 /// This method is called only if ParameterizedProperties are present.324 /// </remarks>325 protected virtual string ParameterizedPropertyToString(PSParameterizedProperty property)326 {327 Diagnostics.Assert(false, "adapter is not called for parameterized properties");328 throw PSTraceSource.NewNotSupportedException();329 }330 331 #endregion parameterized property332 333 #endregion virtual334 335 #region base336 337 #region private338 339 private static Exception NewException(340 Exception e,341 string errorId,342 string targetErrorId,343 string resourceString,344 params object[] parameters)345 {346 object[] newParameters = new object[parameters.Length + 1];347 for (int i = 0; i < parameters.Length; i++)348 {349 newParameters[i + 1] = parameters[i];350 }351 352 Exception ex = e as TargetInvocationException;353 if (ex != null)354 {355 Exception inner = ex.InnerException ?? ex;356 newParameters[0] = inner.Message;357 return new ExtendedTypeSystemException(358 targetErrorId,359 inner,360 resourceString,361 newParameters);362 }363 364 newParameters[0] = e.Message;365 return new ExtendedTypeSystemException(366 errorId,367 e,368 resourceString,369 newParameters);370 }371 372 #endregion private373 374 #region member375 376 internal ConsolidatedString BaseGetTypeNameHierarchy(object obj)377 {378 try379 {380 return GetInternedTypeNameHierarchy(obj);381 }382 catch (ExtendedTypeSystemException) { throw; }383 catch (Exception e)384 {385 throw NewException(386 e,387 "CatchFromBaseGetTypeNameHierarchy",388 "CatchFromBaseGetTypeNameHierarchyTI",389 ExtendedTypeSystem.ExceptionRetrievingTypeNameHierarchy);390 }391 }392 393 internal T BaseGetMember<T>(object obj, string memberName) where T : PSMemberInfo394 {395 try396 {397 return this.GetMember<T>(obj, memberName);398 }399 catch (ExtendedTypeSystemException) { throw; }400 catch (Exception e)401 {402 throw NewException(403 e,404 "CatchFromBaseGetMember",405 "CatchFromBaseGetMemberTI",406 ExtendedTypeSystem.ExceptionGettingMember,407 memberName);408 }409 }410 411 internal T BaseGetFirstMemberOrDefault<T>(object obj, MemberNamePredicate predicate) where T : PSMemberInfo412 {413 try414 {415 return this.GetFirstMemberOrDefault<T>(obj, predicate);416 }417 catch (ExtendedTypeSystemException) { throw; }418 catch (Exception e)419 {420 throw NewException(421 e,422 "CatchFromBaseGetMember",423 "CatchFromBaseGetMemberTI",424 ExtendedTypeSystem.ExceptionGettingMember,425 nameof(predicate));426 }427 }428 429 internal PSMemberInfoInternalCollection<T> BaseGetMembers<T>(object obj) where T : PSMemberInfo430 {431 try432 {433 return this.GetMembers<T>(obj);434 }435 catch (ExtendedTypeSystemException) { throw; }436 catch (Exception e)437 {438 throw NewException(439 e,440 "CatchFromBaseGetMembers",441 "CatchFromBaseGetMembersTI",442 ExtendedTypeSystem.ExceptionGettingMembers);443 }444 }445 446 #endregion member447 448 #region property449 450 internal object BasePropertyGet(PSProperty property)451 {452 try453 {454 return PropertyGet(property);455 }456 catch (TargetInvocationException ex)457 {458 Exception inner = ex.InnerException ?? ex;459 throw new GetValueInvocationException(460 "CatchFromBaseAdapterGetValueTI",461 inner,462 ExtendedTypeSystem.ExceptionWhenGetting,463 property.Name, inner.Message);464 }465 catch (GetValueException) { throw; }466 catch (Exception e)467 {468 throw new GetValueInvocationException(469 "CatchFromBaseAdapterGetValue",470 e,471 ExtendedTypeSystem.ExceptionWhenGetting,472 property.Name, e.Message);473 }474 }475 476 internal void BasePropertySet(PSProperty property, object setValue, bool convert)477 {478 try479 {480 PropertySet(property, setValue, convert);481 }482 catch (TargetInvocationException ex)483 {484 Exception inner = ex.InnerException ?? ex;485 throw new SetValueInvocationException(486 "CatchFromBaseAdapterSetValueTI",487 inner,488 ExtendedTypeSystem.ExceptionWhenSetting,489 property.Name, inner.Message);490 }491 catch (SetValueException) { throw; }492 catch (Exception e)493 {494 throw new SetValueInvocationException(495 "CatchFromBaseAdapterSetValue",496 e,497 ExtendedTypeSystem.ExceptionWhenSetting,498 property.Name, e.Message);499 }500 }501 502 internal bool BasePropertyIsSettable(PSProperty property)503 {504 try505 {506 return this.PropertyIsSettable(property);507 }508 catch (ExtendedTypeSystemException) { throw; }509 catch (Exception e)510 {511 throw NewException(512 e,513 "CatchFromBasePropertyIsSettable",514 "CatchFromBasePropertyIsSettableTI",515 ExtendedTypeSystem.ExceptionRetrievingPropertyWriteState,516 property.Name);517 }518 }519 520 internal bool BasePropertyIsGettable(PSProperty property)521 {522 try523 {524 return this.PropertyIsGettable(property);525 }526 catch (ExtendedTypeSystemException) { throw; }527 catch (Exception e)528 {529 throw NewException(530 e,531 "CatchFromBasePropertyIsGettable",532 "CatchFromBasePropertyIsGettableTI",533 ExtendedTypeSystem.ExceptionRetrievingPropertyReadState,534 property.Name);535 }536 }537 538 internal string BasePropertyType(PSProperty property)539 {540 try541 {542 return this.PropertyType(property, forDisplay: false);543 }544 catch (ExtendedTypeSystemException) { throw; }545 catch (Exception e)546 {547 throw NewException(548 e,549 "CatchFromBasePropertyType",550 "CatchFromBasePropertyTypeTI",551 ExtendedTypeSystem.ExceptionRetrievingPropertyType,552 property.Name);553 }554 }555 556 internal string BasePropertyToString(PSProperty property)557 {558 try559 {560 return this.PropertyToString(property);561 }562 catch (ExtendedTypeSystemException) { throw; }563 catch (Exception e)564 {565 throw NewException(566 e,567 "CatchFromBasePropertyToString",568 "CatchFromBasePropertyToStringTI",569 ExtendedTypeSystem.ExceptionRetrievingPropertyString,570 property.Name);571 }572 }573 574 internal AttributeCollection BasePropertyAttributes(PSProperty property)575 {576 try577 {578 return this.PropertyAttributes(property);579 }580 catch (ExtendedTypeSystemException) { throw; }581 catch (Exception e)582 {583 throw NewException(584 e,585 "CatchFromBasePropertyAttributes",586 "CatchFromBasePropertyAttributesTI",587 ExtendedTypeSystem.ExceptionRetrievingPropertyAttributes,588 property.Name);589 }590 }591 592 #endregion property593 594 #region method595 internal object BaseMethodInvoke(PSMethod method, PSMethodInvocationConstraints invocationConstraints, params object[] arguments)596 {597 try598 {599 return this.MethodInvoke(method, invocationConstraints, arguments);600 }601 catch (TargetInvocationException ex)602 {603 Exception inner = ex.InnerException ?? ex;604 throw new MethodInvocationException(605 "CatchFromBaseAdapterMethodInvokeTI",606 inner,607 ExtendedTypeSystem.MethodInvocationException,608 method.Name,609 arguments.Length,610 inner.Message);611 }612 catch (FlowControlException) { throw; }613 catch (ScriptCallDepthException) { throw; }614 catch (PipelineStoppedException) { throw; }615 catch (MethodException) { throw; }616 catch (Exception e)617 {618 if (method.baseObject is SteppablePipeline619 && (method.Name.Equals("Begin", StringComparison.OrdinalIgnoreCase) ||620 method.Name.Equals("Process", StringComparison.OrdinalIgnoreCase) ||621 method.Name.Equals("End", StringComparison.OrdinalIgnoreCase)))622 {623 throw;624 }625 626 throw new MethodInvocationException(627 "CatchFromBaseAdapterMethodInvoke",628 e,629 ExtendedTypeSystem.MethodInvocationException,630 method.Name,631 arguments.Length,632 e.Message);633 }634 }635 636 internal Collection<string> BaseMethodDefinitions(PSMethod method)637 {638 try639 {640 return this.MethodDefinitions(method);641 }642 catch (ExtendedTypeSystemException) { throw; }643 catch (Exception e)644 {645 throw NewException(646 e,647 "CatchFromBaseMethodDefinitions",648 "CatchFromBaseMethodDefinitionsTI",649 ExtendedTypeSystem.ExceptionRetrievingMethodDefinitions,650 method.Name);651 }652 }653 654 internal string BaseMethodToString(PSMethod method)655 {656 try657 {658 return this.MethodToString(method);659 }660 catch (ExtendedTypeSystemException) { throw; }661 catch (Exception e)662 {663 throw NewException(664 e,665 "CatchFromBaseMethodToString",666 "CatchFromBaseMethodToStringTI",667 ExtendedTypeSystem.ExceptionRetrievingMethodString,668 method.Name);669 }670 }671 #endregion method672 673 #region parameterized property674 internal string BaseParameterizedPropertyType(PSParameterizedProperty property)675 {676 try677 {678 return this.ParameterizedPropertyType(property);679 }680 catch (ExtendedTypeSystemException) { throw; }681 catch (Exception e)682 {683 throw NewException(684 e,685 "CatchFromBaseParameterizedPropertyType",686 "CatchFromBaseParameterizedPropertyTypeTI",687 ExtendedTypeSystem.ExceptionRetrievingParameterizedPropertytype,688 property.Name);689 }690 }691 692 internal bool BaseParameterizedPropertyIsSettable(PSParameterizedProperty property)693 {694 try695 {696 return this.ParameterizedPropertyIsSettable(property);697 }698 catch (ExtendedTypeSystemException) { throw; }699 catch (Exception e)700 {701 throw NewException(702 e,703 "CatchFromBaseParameterizedPropertyIsSettable",704 "CatchFromBaseParameterizedPropertyIsSettableTI",705 ExtendedTypeSystem.ExceptionRetrievingParameterizedPropertyWriteState,706 property.Name);707 }708 }709 710 internal bool BaseParameterizedPropertyIsGettable(PSParameterizedProperty property)711 {712 try713 {714 return this.ParameterizedPropertyIsGettable(property);715 }716 catch (ExtendedTypeSystemException) { throw; }717 catch (Exception e)718 {719 throw NewException(720 e,721 "CatchFromBaseParameterizedPropertyIsGettable",722 "CatchFromBaseParameterizedPropertyIsGettableTI",723 ExtendedTypeSystem.ExceptionRetrievingParameterizedPropertyReadState,724 property.Name);725 }726 }727 728 internal Collection<string> BaseParameterizedPropertyDefinitions(PSParameterizedProperty property)729 {730 try731 {732 return this.ParameterizedPropertyDefinitions(property);733 }734 catch (ExtendedTypeSystemException) { throw; }735 catch (Exception e)736 {737 throw NewException(738 e,739 "CatchFromBaseParameterizedPropertyDefinitions",740 "CatchFromBaseParameterizedPropertyDefinitionsTI",741 ExtendedTypeSystem.ExceptionRetrievingParameterizedPropertyDefinitions,742 property.Name);743 }744 }745 746 internal object BaseParameterizedPropertyGet(PSParameterizedProperty property, params object[] arguments)747 {748 try749 {750 return this.ParameterizedPropertyGet(property, arguments);751 }752 catch (TargetInvocationException ex)753 {754 Exception inner = ex.InnerException ?? ex;755 throw new GetValueInvocationException(756 "CatchFromBaseAdapterParameterizedPropertyGetValueTI",757 inner,758 ExtendedTypeSystem.ExceptionWhenGetting,759 property.Name,760 inner.Message);761 }762 catch (GetValueException) { throw; }763 catch (Exception e)764 {765 throw new GetValueInvocationException(766 "CatchFromBaseParameterizedPropertyAdapterGetValue",767 e,768 ExtendedTypeSystem.ExceptionWhenGetting,769 property.Name,770 e.Message);771 }772 }773 774 internal void BaseParameterizedPropertySet(PSParameterizedProperty property, object setValue, params object[] arguments)775 {776 try777 {778 this.ParameterizedPropertySet(property, setValue, arguments);779 }780 catch (TargetInvocationException ex)781 {782 Exception inner = ex.InnerException ?? ex;783 throw new SetValueInvocationException(784 "CatchFromBaseAdapterParameterizedPropertySetValueTI",785 inner,786 ExtendedTypeSystem.ExceptionWhenSetting,787 property.Name,788 inner.Message);789 }790 catch (SetValueException) { throw; }791 catch (Exception e)792 {793 throw new SetValueInvocationException(794 "CatchFromBaseAdapterParameterizedPropertySetValue",795 e,796 ExtendedTypeSystem.ExceptionWhenSetting,797 property.Name,798 e.Message);799 }800 }801 802 internal string BaseParameterizedPropertyToString(PSParameterizedProperty property)803 {804 try805 {806 return this.ParameterizedPropertyToString(property);807 }808 catch (ExtendedTypeSystemException) { throw; }809 catch (Exception e)810 {811 throw NewException(812 e,813 "CatchFromBaseParameterizedPropertyToString",814 "CatchFromBaseParameterizedPropertyToStringTI",815 ExtendedTypeSystem.ExceptionRetrievingParameterizedPropertyString,816 property.Name);817 }818 }819 820 #endregion parameterized property821 822 #region Internal Helper Methods823 824 private static Type GetArgumentType(object argument, bool isByRefParameter)825 {826 if (argument == null)827 {828 return typeof(LanguagePrimitives.Null);829 }830 831 if (isByRefParameter && argument is PSReference psref)832 {833 return GetArgumentType(PSObject.Base(psref.Value), isByRefParameter: false);834 }835 836 return GetObjectType(argument, debase: false);837 }838 839 internal static ConversionRank GetArgumentConversionRank(object argument, Type parameterType, bool isByRef, bool allowCastingToByRefLikeType)840 {841 Type fromType = null;842 ConversionRank rank = ConversionRank.None;843 844 if (allowCastingToByRefLikeType && parameterType.IsByRefLike)845 {846 // When resolving best method for use in binders, we can accept implicit/explicit casting conversions to847 // a ByRef-like target type, because when generating IL from a call site with the binder, the IL includes848 // the casting operation. However, we don't accept such conversions when it's for invoking the method via849 // reflection, because reflection just doesn't support ByRef-like type.850 fromType = GetArgumentType(PSObject.Base(argument), isByRefParameter: false);851 if (fromType != typeof(LanguagePrimitives.Null))852 {853 LanguagePrimitives.FigureCastConversion(fromType, parameterType, ref rank);854 }855 856 return rank;857 }858 859 fromType = GetArgumentType(argument, isByRef);860 rank = LanguagePrimitives.GetConversionRank(fromType, parameterType);861 862 if (rank == ConversionRank.None)863 {864 fromType = GetArgumentType(PSObject.Base(argument), isByRef);865 rank = LanguagePrimitives.GetConversionRank(fromType, parameterType);866 }867 868 return rank;869 }870 871 private static ParameterInformation[] ExpandParameters(int argCount, ParameterInformation[] parameters, Type elementType)872 {873 Diagnostics.Assert(parameters[parameters.Length - 1].isParamArray, "ExpandParameters shouldn't be called on non-param method");874 875 ParameterInformation[] newParameters = new ParameterInformation[argCount];876 Array.Copy(parameters, newParameters, parameters.Length - 1);877 for (int i = parameters.Length - 1; i < argCount; ++i)878 {879 newParameters[i] = new ParameterInformation(elementType, false, null, false);880 }881 882 return newParameters;883 }884 885 /// <summary>886 /// Compare the 2 methods, determining which method is better.887 /// </summary>888 /// <returns>1 if method1 is better, -1 if method2 is better, 0 otherwise.</returns>889 private static int CompareOverloadCandidates(OverloadCandidate candidate1, OverloadCandidate candidate2, object[] arguments)890 {891 Diagnostics.Assert(candidate1.conversionRanks.Length == candidate2.conversionRanks.Length,892 "should have same number of conversions regardless of the number of parameters - default arguments are not included here");893 894 ParameterInformation[] params1 = candidate1.expandedParameters ?? candidate1.parameters;895 ParameterInformation[] params2 = candidate2.expandedParameters ?? candidate2.parameters;896 897 int betterCount = 0;898 int multiplier = candidate1.conversionRanks.Length;899 for (int i = 0; i < candidate1.conversionRanks.Length; ++i, --multiplier)900 {901 if (candidate1.conversionRanks[i] < candidate2.conversionRanks[i])902 {903 betterCount -= multiplier;904 }905 else if (candidate1.conversionRanks[i] > candidate2.conversionRanks[i])906 {907 betterCount += multiplier;908 }909 else if (candidate1.conversionRanks[i] == ConversionRank.UnrelatedArrays)910 {911 // If both are unrelated arrays, then use the element type conversions instead.912 Type argElemType = EffectiveArgumentType(arguments[i]).GetElementType();913 ConversionRank rank1 = LanguagePrimitives.GetConversionRank(argElemType, params1[i].parameterType.GetElementType());914 ConversionRank rank2 = LanguagePrimitives.GetConversionRank(argElemType, params2[i].parameterType.GetElementType());915 if (rank1 < rank2)916 {917 betterCount -= multiplier;918 }919 else if (rank1 > rank2)920 {921 betterCount += multiplier;922 }923 }924 }925 926 if (betterCount == 0)927 {928 multiplier = candidate1.conversionRanks.Length;929 for (int i = 0; i < candidate1.conversionRanks.Length; ++i, multiplier = Math.Abs(multiplier) - 1)930 {931 // The following rather tricky logic tries to pick the best method in 2 very different cases -932 // - Pick the most specific method when conversions aren't losing information933 // - Pick the most general method when conversions will lose information.934 // Consider:935 // f(uint32), f(decimal), call with f([byte]$i)936 // in this case, we want to call f(uint32) because it is more specific937 // while not losing information938 // f(byte), f(int16), call with f([int]$i)939 // in this case, we want to call f(int16) because it is more general,940 // we know we could lose information with either call, but we will lose941 // less information calling f(int16).942 ConversionRank rank1 = candidate1.conversionRanks[i];943 ConversionRank rank2 = candidate2.conversionRanks[i];944 if (rank1 < ConversionRank.NullToValue || rank2 < ConversionRank.NullToValue)945 {946 // The tie breaking rules here do not apply to conversions that are not947 // numeric or inheritance related.948 continue;949 }950 951 if ((rank1 >= ConversionRank.NumericImplicit) != (rank2 >= ConversionRank.NumericImplicit))952 {953 // Skip trying to break ties when argument conversions are not both implicit or both954 // explicit. If we have that situation, there are multiple arguments and an955 // ambiguity is probably the best choice.956 continue;957 }958 959 // We will now compare the parameter types, ignoring the actual argument type. To choose960 // the right method, we need to know if we want the "most specific" or the "most general".961 // If we have implicit argument conversions, we'll want the most specific, so invert the multiplier.962 if (rank1 >= ConversionRank.NumericImplicit)963 {964 multiplier = -multiplier;965 }966 967 // With a positive multiplier, we'll choose the "most general" type, and a negative968 // multiplier will choose the "most specific".969 rank1 = LanguagePrimitives.GetConversionRank(params1[i].parameterType, params2[i].parameterType);970 rank2 = LanguagePrimitives.GetConversionRank(params2[i].parameterType, params1[i].parameterType);971 if (rank1 < rank2)972 {973 betterCount += multiplier;974 }975 else if (rank1 > rank2)976 {977 betterCount -= multiplier;978 }979 }980 }981 982 if (betterCount == 0)983 {984 // Check if parameters are the same. If so, we have a few tiebreakering rules down below.985 for (int i = 0; i < candidate1.conversionRanks.Length; ++i)986 {987 if (params1[i].parameterType != params2[i].parameterType)988 {989 return 0;990 }991 }992 993 // Apply tie breaking rules, related to expanded parameters994 if (candidate1.expandedParameters != null && candidate2.expandedParameters != null)995 {996 // Both are using expanded parameters. The one with more parameters is better997 return (candidate1.parameters.Length > candidate2.parameters.Length) ? 1 : -1;998 }999 else if (candidate1.expandedParameters != null)1000 {1001 return -1;1002 }1003 else if (candidate2.expandedParameters != null)1004 {1005 return 1;1006 }1007 1008 // Apply tie breaking rules, related to specificity of parameters1009 betterCount = CompareTypeSpecificity(candidate1, candidate2);1010 }1011 1012 // The methods with fewer parameter wins1013 // Need to revisit this if we support named arguments1014 if (betterCount == 0)1015 {1016 if (candidate1.parameters.Length < candidate2.parameters.Length)1017 {1018 return 1;1019 }1020 else if (candidate1.parameters.Length > candidate2.parameters.Length)1021 {1022 return -1;1023 }1024 }1025 1026 return betterCount;1027 }1028 1029 private static OverloadCandidate FindBestCandidate(List<OverloadCandidate> candidates, object[] arguments)1030 {1031 Dbg.Assert(candidates != null, "Caller should verify candidates != null");1032 1033 OverloadCandidate bestCandidateSoFar = null;1034 bool multipleBestCandidates = false;1035 1036 for (int i = 0; i < candidates.Count; i++)1037 {1038 OverloadCandidate currentCandidate = candidates[i];1039 if (bestCandidateSoFar == null) // first iteration1040 {1041 bestCandidateSoFar = currentCandidate;1042 continue;1043 }1044 1045 int comparisonResult = CompareOverloadCandidates(bestCandidateSoFar, currentCandidate, arguments);1046 if (comparisonResult == 0)1047 {1048 multipleBestCandidates = true;1049 }1050 else if (comparisonResult < 0)1051 {1052 bestCandidateSoFar = currentCandidate;1053 multipleBestCandidates = false;1054 }1055 }1056 1057 Dbg.Assert(1058 !candidates.Any(otherCandidate => otherCandidate != bestCandidateSoFar && CompareOverloadCandidates(otherCandidate, bestCandidateSoFar, arguments) > 0),1059 "No other candidates are better than bestCandidateSoFar");1060 1061 return multipleBestCandidates ? null : bestCandidateSoFar;1062 }1063 1064 private static OverloadCandidate FindBestCandidate(List<OverloadCandidate> candidates, object[] arguments, PSMethodInvocationConstraints invocationConstraints)1065 {1066 List<OverloadCandidate> filteredCandidates = candidates.Where(candidate => IsInvocationConstraintSatisfied(candidate, invocationConstraints)).ToList();1067 if (filteredCandidates.Count > 0)1068 {1069 candidates = filteredCandidates;1070 }1071 1072 OverloadCandidate bestCandidate = FindBestCandidate(candidates, arguments);1073 return bestCandidate;1074 }1075 1076 private static int CompareTypeSpecificity(Type type1, Type type2)1077 {1078 if (type1.IsGenericParameter || type2.IsGenericParameter)1079 {1080 int result = 0;1081 if (type1.IsGenericParameter)1082 {1083 result -= 1;1084 }1085 1086 if (type2.IsGenericParameter)1087 {1088 result += 1;1089 }1090 1091 return result;1092 }1093 1094 if (type1.IsArray)1095 {1096 Dbg.Assert(type2.IsArray, "Caller should verify that both overload candidates have the same parameter types");1097 Dbg.Assert(type1.GetArrayRank() == type2.GetArrayRank(), "Caller should verify that both overload candidates have the same parameter types");1098 return CompareTypeSpecificity(type1.GetElementType(), type2.GetElementType());1099 }1100 1101 if (type1.IsGenericType)1102 {1103 Dbg.Assert(type2.IsGenericType, "Caller should verify that both overload candidates have the same parameter types");1104 Dbg.Assert(type1.GetGenericTypeDefinition() == type2.GetGenericTypeDefinition(), "Caller should verify that both overload candidates have the same parameter types");1105 return CompareTypeSpecificity(type1.GetGenericArguments(), type2.GetGenericArguments());1106 }1107 1108 return 0;1109 }1110 1111 private static int CompareTypeSpecificity(Type[] params1, Type[] params2)1112 {1113 Dbg.Assert(params1.Length == params2.Length, "Caller should verify that both overload candidates have the same number of parameters");1114 1115 bool candidate1hasAtLeastOneMoreSpecificParameter = false;1116 bool candidate2hasAtLeastOneMoreSpecificParameter = false;1117 for (int i = 0; i < params1.Length; ++i)1118 {1119 int specificityComparison = CompareTypeSpecificity(params1[i], params2[i]);1120 if (specificityComparison > 0)1121 {1122 candidate1hasAtLeastOneMoreSpecificParameter = true;1123 }1124 else if (specificityComparison < 0)1125 {1126 candidate2hasAtLeastOneMoreSpecificParameter = true;1127 }1128 1129 if (candidate1hasAtLeastOneMoreSpecificParameter && candidate2hasAtLeastOneMoreSpecificParameter)1130 {1131 break;1132 }1133 }1134 1135 if (candidate1hasAtLeastOneMoreSpecificParameter && !candidate2hasAtLeastOneMoreSpecificParameter)1136 {1137 return 1;1138 }1139 else if (candidate2hasAtLeastOneMoreSpecificParameter && !candidate1hasAtLeastOneMoreSpecificParameter)1140 {1141 return -1;1142 }1143 else1144 {1145 return 0;1146 }1147 }1148 1149 /// <summary>1150 /// Returns -1 if <paramref name="candidate1"/> is less specific than <paramref name="candidate2"/>1151 /// (1 otherwise, or 0 if both are equally specific or non-comparable)1152 /// </summary>1153 private static int CompareTypeSpecificity(OverloadCandidate candidate1, OverloadCandidate candidate2)1154 {1155 if (!(candidate1.method.isGeneric || candidate2.method.isGeneric))1156 {1157 return 0;1158 }1159 1160 Type[] params1 = GetGenericMethodDefinitionIfPossible(candidate1.method.method).GetParameters().Select(static p => p.ParameterType).ToArray();1161 Type[] params2 = GetGenericMethodDefinitionIfPossible(candidate2.method.method).GetParameters().Select(static p => p.ParameterType).ToArray();1162 return CompareTypeSpecificity(params1, params2);1163 }1164 1165 private static MethodBase GetGenericMethodDefinitionIfPossible(MethodBase method)1166 {1167 if (method.IsGenericMethod && !method.IsGenericMethodDefinition)1168 {1169 MethodInfo methodInfo = method as MethodInfo;1170 if (methodInfo != null)1171 {1172 return methodInfo.GetGenericMethodDefinition();1173 }1174 }1175 1176 return method;1177 }1178 1179 [DebuggerDisplay("OverloadCandidate: {method.methodDefinition}")]1180 private sealed class OverloadCandidate1181 {1182 internal MethodInformation method;1183 internal ParameterInformation[] parameters;1184 internal ParameterInformation[] expandedParameters;1185 internal ConversionRank[] conversionRanks;1186 1187 internal OverloadCandidate(MethodInformation method, int argCount)1188 {1189 this.method = method;1190 this.parameters = method.parameters;1191 conversionRanks = new ConversionRank[argCount];1192 }1193 }1194 1195 private static bool IsInvocationTargetConstraintSatisfied(MethodInformation method, PSMethodInvocationConstraints invocationConstraints)1196 {1197 Dbg.Assert(method != null, "Caller should verify method != null");1198 1199 if (method.method == null)1200 {