mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Improve PSMethod-to-Delegate conversion (#6570)
Two small improvements: 1. Avoid unnecessary reflection in `ConvertPSMethodInfoToDelegate`. `PSMethod` already has the `MethodInfo` information with its `adapterData` field. 2. Avoid creating the generic `PSMethod<>` type for `PSMethod` that represents constructors, because constructors cannot be converted to a delegate anyways. In case that the `PSMethod` represents constructors, we use a simple `PSMethod` instance instead. Also, rename the type `Unit` to `VOID` to make it more readable, since that type represents `typeof(void)`.
This commit is contained in:
@@ -2345,7 +2345,7 @@ namespace System.Management.Automation
|
||||
/// <summary>
|
||||
/// Cache delegate to the ctor of PSMethod<> with a template parameter derived from the methodInformationStructures.
|
||||
/// </summary>
|
||||
internal Func<string, DotNetAdapter, object, DotNetAdapter.MethodCacheEntry, bool, bool, PSMethod> psmethodCtor;
|
||||
internal Func<string, DotNetAdapter, object, DotNetAdapter.MethodCacheEntry, bool, bool, PSMethod> PSMethodCtor;
|
||||
|
||||
internal MethodCacheEntry(MethodBase[] methods)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Management.Automation.Language;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
@@ -20,7 +21,7 @@ using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Diagnostics.CodeAnalysis; // for fxcop
|
||||
using Dbg = System.Management.Automation.Diagnostics;
|
||||
using System.Reflection.Emit;
|
||||
using MethodCacheEntry = System.Management.Automation.DotNetAdapter.MethodCacheEntry;
|
||||
|
||||
#if !CORECLR
|
||||
// System.DirectoryServices are not in CoreCLR
|
||||
@@ -3210,31 +3211,24 @@ namespace System.Management.Automation
|
||||
IFormatProvider formatProvider,
|
||||
TypeTable backupTable)
|
||||
{
|
||||
PSMethod psMethod;
|
||||
// We can only possibly convert PSMethod instance of the type PSMethod<T>.
|
||||
// Such a PSMethod essentially represents a set of .NET method overloads.
|
||||
var psMethod = (PSMethod)valueToConvert;
|
||||
|
||||
try
|
||||
{
|
||||
psMethod = (PSMethod) valueToConvert;
|
||||
|
||||
var maybeType = psMethod.instance as Type;
|
||||
var methodInfoCandiates = maybeType != null
|
||||
? maybeType.GetMethods(BindingFlags.Static | BindingFlags.Public)
|
||||
: psMethod.instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
var methods = (MethodCacheEntry)psMethod.adapterData;
|
||||
var isStatic = psMethod.instance is Type;
|
||||
var targetMethodInfo = resultType.GetMethod("Invoke");
|
||||
|
||||
var comparator = new DelegateArgsComparator(targetMethodInfo);
|
||||
|
||||
foreach (var candidate in methodInfoCandiates)
|
||||
foreach (var methodInformation in methods.methodInformationStructures)
|
||||
{
|
||||
if (candidate.Name != psMethod.Name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var candidate = (MethodInfo)methodInformation.method;
|
||||
if (comparator.SignatureMatches(candidate.ReturnType, candidate.GetParameters()))
|
||||
{
|
||||
return maybeType != null
|
||||
? candidate.CreateDelegate(resultType)
|
||||
: candidate.CreateDelegate(resultType, psMethod.instance);
|
||||
return isStatic ? candidate.CreateDelegate(resultType)
|
||||
: candidate.CreateDelegate(resultType, psMethod.instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3246,12 +3240,12 @@ namespace System.Management.Automation
|
||||
valueToConvert.ToString(), resultType.ToString(), e.Message);
|
||||
}
|
||||
|
||||
var msg = String.Format(ExtendedTypeSystem.PSMethodToDelegateNoMatchingOverLoad, psMethod, resultType);
|
||||
var msg = String.Format(ExtendedTypeSystem.PSMethodToDelegateNoMatchingOverLoad, psMethod, resultType);
|
||||
typeConversion.WriteLine($"PSMethod to Delegate exception: \"{msg}\".");
|
||||
throw new PSInvalidCastException("InvalidCastExceptionPSMethodToDelegate", null,
|
||||
ExtendedTypeSystem.InvalidCastExceptionWithInnerException,
|
||||
valueToConvert.ToString(), resultType.ToString(), msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static object ConvertToNullable(object valueToConvert,
|
||||
Type resultType,
|
||||
@@ -4789,7 +4783,6 @@ namespace System.Management.Automation
|
||||
while (signatureEnumerator.MoveNext())
|
||||
{
|
||||
var candidate = signatureEnumerator.Current.GetMethod("Invoke");
|
||||
|
||||
if (comparator.SignatureMatches(candidate.ReturnType, candidate.GetParameters()))
|
||||
{
|
||||
return CacheConversion<Delegate>(fromType, toType, LanguagePrimitives.ConvertPSMethodInfoToDelegate, ConversionRank.Language);
|
||||
@@ -4824,7 +4817,7 @@ namespace System.Management.Automation
|
||||
private bool ParameterTypesMatches(ParameterInfo[] arguments)
|
||||
{
|
||||
var argsCount = _targetParametersInfos.Length;
|
||||
// void is encoded as typeof(Unit) in the PSMethod<MethodGroup<>> as the last parameter
|
||||
// void is encoded as typeof(VOID) in the PSMethod<MethodGroup<>> as the last parameter
|
||||
if (arguments.Length != argsCount)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -2642,11 +2642,17 @@ namespace System.Management.Automation
|
||||
|
||||
internal static PSMethod Create(string name, DotNetAdapter dotNetInstanceAdapter, object baseObject, DotNetAdapter.MethodCacheEntry method, bool isSpecial, bool isHidden)
|
||||
{
|
||||
if (method.psmethodCtor == null)
|
||||
if (method[0].method is ConstructorInfo)
|
||||
{
|
||||
method.psmethodCtor = CreatePSMethodConstructor(method.methodInformationStructures);
|
||||
// Constructor cannot be converted to a delegate, so just return a simple PSMethod instance
|
||||
return new PSMethod(name, dotNetInstanceAdapter, baseObject, method, isSpecial, isHidden);
|
||||
}
|
||||
return method.psmethodCtor.Invoke(name, dotNetInstanceAdapter, baseObject, method, isSpecial, isHidden);
|
||||
|
||||
if (method.PSMethodCtor == null)
|
||||
{
|
||||
method.PSMethodCtor = CreatePSMethodConstructor(method.methodInformationStructures);
|
||||
}
|
||||
return method.PSMethodCtor.Invoke(name, dotNetInstanceAdapter, baseObject, method, isSpecial, isHidden);
|
||||
}
|
||||
|
||||
static Type GetMethodGroupType(MethodInfo methodInfo)
|
||||
@@ -2697,7 +2703,7 @@ namespace System.Management.Automation
|
||||
{
|
||||
if (type == typeof(void))
|
||||
{
|
||||
return typeof(Unit);
|
||||
return typeof(VOID);
|
||||
}
|
||||
if (type == typeof(TypedReference))
|
||||
{
|
||||
@@ -2742,7 +2748,7 @@ namespace System.Management.Automation
|
||||
sourceType = sourceType.GenericTypeArguments[0];
|
||||
}
|
||||
|
||||
if (targetType == typeof(void) && sourceType == typeof(Unit))
|
||||
if (targetType == typeof(void) && sourceType == typeof(VOID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -2783,21 +2789,14 @@ namespace System.Management.Automation
|
||||
|
||||
private static Func<string, DotNetAdapter, object, object, bool, bool, PSMethod> CreatePSMethodConstructor(MethodInformation[] methods)
|
||||
{
|
||||
// Produce the PSMethod creator for MethodInfo objects
|
||||
var types = new Type[methods.Length];
|
||||
for (int i = 0; i < methods.Length; i++)
|
||||
{
|
||||
var mb = methods[i].method;
|
||||
|
||||
if (mb is MethodInfo mi)
|
||||
{
|
||||
types[i] = GetMethodGroupType(mi);
|
||||
}
|
||||
else
|
||||
{
|
||||
types[i] = typeof(Unit);
|
||||
}
|
||||
types[i] = GetMethodGroupType((MethodInfo)methods[i].method);
|
||||
}
|
||||
var methodGroupType = CreateMethodGroup(types, 0, types.Length);
|
||||
|
||||
var methodGroupType = CreateMethodGroup(types, 0, types.Length);
|
||||
Type psMethodType = typeof(PSMethod<>).MakeGenericType(methodGroupType);
|
||||
var delegateType = typeof(Func<string, DotNetAdapter, object, object, bool, bool, PSMethod>);
|
||||
return (Func<string, DotNetAdapter, object, object, bool, bool, PSMethod>)Delegate.CreateDelegate(delegateType, psMethodType.GetMethod("Create", BindingFlags.NonPublic|BindingFlags.Static));
|
||||
@@ -2946,9 +2945,9 @@ namespace System.Management.Automation
|
||||
internal class MethodGroup<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> : MethodGroup { }
|
||||
internal class MethodGroup<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32> : MethodGroup { }
|
||||
|
||||
class Unit
|
||||
class VOID
|
||||
{
|
||||
private Unit() { }
|
||||
private VOID() { }
|
||||
}
|
||||
|
||||
internal struct PSMethodSignatureEnumerator : IEnumerator<Type>
|
||||
|
||||
Reference in New Issue
Block a user