From 96c97c2cf48a4dc2bd9365c67f442b68514a007c Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Fri, 25 Dec 2020 05:56:36 +0100 Subject: [PATCH] Move few more methods to shared RuntimeType (#46383) --- .../src/System/RuntimeType.CoreCLR.cs | 398 ------------------- .../src/System/RuntimeType.cs | 401 +++++++++++++++++++ .../src/System/RuntimeType.Mono.cs | 425 --------------------- 3 files changed, 401 insertions(+), 823 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 7b4f322..26bc4e1 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -1935,31 +1935,6 @@ namespace System throw new SystemException(); } - private static void ThrowIfTypeNeverValidGenericArgument(RuntimeType type) - { - if (type.IsPointer || type.IsByRef || type == typeof(void)) - throw new ArgumentException( - SR.Format(SR.Argument_NeverValidGenericArgument, type)); - } - - internal static void SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParamters) - { - if (genericArguments == null) - throw new ArgumentNullException(); - - for (int i = 0; i < genericArguments.Length; i++) - { - if (genericArguments[i] == null) - throw new ArgumentNullException(); - - ThrowIfTypeNeverValidGenericArgument(genericArguments[i]); - } - - if (genericArguments.Length != genericParamters.Length) - throw new ArgumentException( - SR.Format(SR.Argument_NotEnoughGenArguments, genericArguments.Length, genericParamters.Length)); - } - internal static void ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception? e) { RuntimeType[]? typeContext = null; @@ -3348,12 +3323,6 @@ namespace System #region Invoke Member - private const BindingFlags MemberBindingMask = (BindingFlags)0x000000FF; - private const BindingFlags InvocationMask = (BindingFlags)0x0000FF00; - private const BindingFlags BinderNonCreateInstance = BindingFlags.InvokeMethod | BinderGetSetField | BinderGetSetProperty; - private const BindingFlags BinderGetSetProperty = BindingFlags.GetProperty | BindingFlags.SetProperty; - private const BindingFlags BinderGetSetField = BindingFlags.GetField | BindingFlags.SetField; - private const BindingFlags BinderNonFieldGetSet = (BindingFlags)0x00FFF300; private static readonly RuntimeType s_typedRef = (RuntimeType)typeof(TypedReference); [MethodImpl(MethodImplOptions.InternalCall)] @@ -3469,373 +3438,6 @@ namespace System throw new ArgumentException(SR.Format(SR.Arg_ObjObjEx, value.GetType(), this)); } - [DebuggerStepThrough] - [DebuggerHidden] - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public override object? InvokeMember( - string name, BindingFlags bindingFlags, Binder? binder, object? target, - object?[]? providedArgs, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParams) - { - if (IsGenericParameter) - throw new InvalidOperationException(SR.Arg_GenericParameter); - - if ((bindingFlags & InvocationMask) == 0) - // "Must specify binding flags describing the invoke operation required." - throw new ArgumentException(SR.Arg_NoAccessSpec, nameof(bindingFlags)); - - // Provide a default binding mask if none is provided - if ((bindingFlags & MemberBindingMask) == 0) - { - bindingFlags |= BindingFlags.Instance | BindingFlags.Public; - - if ((bindingFlags & BindingFlags.CreateInstance) == 0) - bindingFlags |= BindingFlags.Static; - } - - // There must not be more named parameters than provided arguments - if (namedParams != null) - { - if (providedArgs != null) - { - if (namedParams.Length > providedArgs.Length) - throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); - } - else - { - if (namedParams.Length != 0) - throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); - } - } - -#if FEATURE_COMINTEROP - if (target != null && target.GetType().IsCOMObject) - { - const BindingFlags ClassicBindingMask = - BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty | - BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty; - - if ((bindingFlags & ClassicBindingMask) == 0) - throw new ArgumentException(SR.Arg_COMAccess, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.GetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0) - throw new ArgumentException(SR.Arg_PropSetGet, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0) - throw new ArgumentException(SR.Arg_PropSetInvoke, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.SetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.SetProperty) != 0) - throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.PutDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutDispProperty) != 0) - throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.PutRefDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutRefDispProperty) != 0) - throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); - - if (name == null) - throw new ArgumentNullException(nameof(name)); - - bool[]? isByRef = modifiers?[0].IsByRefArray; - - // pass LCID_ENGLISH_US if no explicit culture is specified to match the behavior of VB - int lcid = (culture == null ? 0x0409 : culture.LCID); - - // If a request to not wrap exceptions was made, we will unwrap - // the TargetInvocationException since that is what will be thrown. - bool unwrapExceptions = (bindingFlags & BindingFlags.DoNotWrapExceptions) != 0; - try - { - return InvokeDispMethod(name, bindingFlags, target, providedArgs, isByRef, lcid, namedParams); - } - catch (TargetInvocationException e) when (unwrapExceptions) - { - // For target invocation exceptions, we need to unwrap the inner exception and - // re-throw it. - throw e.InnerException!; - } - } -#endif // FEATURE_COMINTEROP - - if (namedParams != null && Array.IndexOf(namedParams, null!) != -1) - throw new ArgumentException(SR.Arg_NamedParamNull, nameof(namedParams)); - - int argCnt = (providedArgs != null) ? providedArgs.Length : 0; - - binder ??= DefaultBinder; - - // Delegate to Activator.CreateInstance - if ((bindingFlags & BindingFlags.CreateInstance) != 0) - { - if ((bindingFlags & BindingFlags.CreateInstance) != 0 && (bindingFlags & BinderNonCreateInstance) != 0) - // "Can not specify both CreateInstance and another access type." - throw new ArgumentException(SR.Arg_CreatInstAccess, nameof(bindingFlags)); - - return Activator.CreateInstance(this, bindingFlags, binder, providedArgs, culture); - } - - // PutDispProperty and\or PutRefDispProperty ==> SetProperty. - if ((bindingFlags & (BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty)) != 0) - bindingFlags |= BindingFlags.SetProperty; - - if (name == null) - throw new ArgumentNullException(nameof(name)); - - if (name.Length == 0 || name.Equals("[DISPID=0]")) - { - // in InvokeMember we always pretend there is a default member if none is provided and we make it ToString - name = GetDefaultMemberName()! ?? "ToString"; - } - - // GetField or SetField - bool IsGetField = (bindingFlags & BindingFlags.GetField) != 0; - bool IsSetField = (bindingFlags & BindingFlags.SetField) != 0; - - if (IsGetField || IsSetField) - { - if (IsGetField) - { - if (IsSetField) - throw new ArgumentException(SR.Arg_FldSetGet, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.SetProperty) != 0) - throw new ArgumentException(SR.Arg_FldGetPropSet, nameof(bindingFlags)); - } - else - { - Debug.Assert(IsSetField); - - if (providedArgs == null) - throw new ArgumentNullException(nameof(providedArgs)); - - if ((bindingFlags & BindingFlags.GetProperty) != 0) - throw new ArgumentException(SR.Arg_FldSetPropGet, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - throw new ArgumentException(SR.Arg_FldSetInvoke, nameof(bindingFlags)); - } - - // Lookup Field - FieldInfo? selFld = null; - FieldInfo[]? flds = GetMember(name, MemberTypes.Field, bindingFlags) as FieldInfo[]; - - Debug.Assert(flds != null); - - if (flds.Length == 1) - { - selFld = flds[0]; - } - else if (flds.Length > 0) - { - selFld = binder.BindToField(bindingFlags, flds, IsGetField ? Empty.Value : providedArgs![0]!, culture); - } - - if (selFld != null) - { - // Invocation on a field - if (selFld.FieldType.IsArray || ReferenceEquals(selFld.FieldType, typeof(Array))) - { - // Invocation of an array Field - int idxCnt; - if ((bindingFlags & BindingFlags.GetField) != 0) - { - idxCnt = argCnt; - } - else - { - idxCnt = argCnt - 1; - } - - if (idxCnt > 0) - { - // Verify that all of the index values are ints - int[] idx = new int[idxCnt]; - for (int i = 0; i < idxCnt; i++) - { - try - { - idx[i] = ((IConvertible)providedArgs![i]!).ToInt32(null); - } - catch (InvalidCastException) - { - throw new ArgumentException(SR.Arg_IndexMustBeInt); - } - } - - // Set or get the value... - Array a = (Array)selFld.GetValue(target)!; - - // Set or get the value in the array - if ((bindingFlags & BindingFlags.GetField) != 0) - { - return a.GetValue(idx); - } - else - { - a.SetValue(providedArgs![idxCnt], idx); - return null; - } - } - } - - if (IsGetField) - { - if (argCnt != 0) - throw new ArgumentException(SR.Arg_FldGetArgErr, nameof(bindingFlags)); - - return selFld.GetValue(target); - } - else - { - if (argCnt != 1) - throw new ArgumentException(SR.Arg_FldSetArgErr, nameof(bindingFlags)); - - selFld.SetValue(target, providedArgs![0], bindingFlags, binder, culture); - return null; - } - } - - if ((bindingFlags & BinderNonFieldGetSet) == 0) - throw new MissingFieldException(FullName, name); - } - - // @Legacy - This is RTM behavior - bool isGetProperty = (bindingFlags & BindingFlags.GetProperty) != 0; - bool isSetProperty = (bindingFlags & BindingFlags.SetProperty) != 0; - - if (isGetProperty || isSetProperty) - { - if (isGetProperty) - { - Debug.Assert(!IsSetField); - - if (isSetProperty) - throw new ArgumentException(SR.Arg_PropSetGet, nameof(bindingFlags)); - } - else - { - Debug.Assert(isSetProperty); - - Debug.Assert(!IsGetField); - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - throw new ArgumentException(SR.Arg_PropSetInvoke, nameof(bindingFlags)); - } - } - - MethodInfo[]? finalists = null; - MethodInfo? finalist = null; - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - { - // Lookup Methods - MethodInfo[] semiFinalists = (GetMember(name, MemberTypes.Method, bindingFlags) as MethodInfo[])!; - List? results = null; - - for (int i = 0; i < semiFinalists.Length; i++) - { - MethodInfo semiFinalist = semiFinalists[i]; - Debug.Assert(semiFinalist != null); - - if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) - continue; - - if (finalist == null) - { - finalist = semiFinalist; - } - else - { - results ??= new List(semiFinalists.Length) { finalist }; - results.Add(semiFinalist); - } - } - - if (results != null) - { - Debug.Assert(results.Count > 1); - finalists = results.ToArray(); - } - } - - Debug.Assert(finalists == null || finalist != null); - - // BindingFlags.GetProperty or BindingFlags.SetProperty - if (finalist == null && isGetProperty || isSetProperty) - { - // Lookup Property - PropertyInfo[] semiFinalists = (GetMember(name, MemberTypes.Property, bindingFlags) as PropertyInfo[])!; - List? results = null; - - for (int i = 0; i < semiFinalists.Length; i++) - { - MethodInfo? semiFinalist = null; - - if (isSetProperty) - { - semiFinalist = semiFinalists[i].GetSetMethod(true); - } - else - { - semiFinalist = semiFinalists[i].GetGetMethod(true); - } - - if (semiFinalist == null) - continue; - - if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) - continue; - - if (finalist == null) - { - finalist = semiFinalist; - } - else - { - results ??= new List(semiFinalists.Length) { finalist }; - results.Add(semiFinalist); - } - } - - if (results != null) - { - Debug.Assert(results.Count > 1); - finalists = results.ToArray(); - } - } - - if (finalist != null) - { - // Invoke - if (finalists == null && - argCnt == 0 && - finalist.GetParametersNoCopy().Length == 0 && - (bindingFlags & BindingFlags.OptionalParamBinding) == 0) - { - return finalist.Invoke(target, bindingFlags, binder, providedArgs, culture); - } - - finalists ??= new MethodInfo[] { finalist }; - providedArgs ??= Array.Empty(); - object? state = null; - MethodBase? invokeMethod = null; - - try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs!, modifiers, culture, namedParams, out state); } - catch (MissingMethodException) { } - - if (invokeMethod == null) - throw new MissingMethodException(FullName, name); - - object? result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); - - if (state != null) - binder.ReorderArgumentArray(ref providedArgs, state); - - return result; - } - - throw new MissingMethodException(FullName, name); - } - #endregion #endregion diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 6bc3ddf..88c593c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; @@ -367,6 +369,380 @@ namespace System return false; } + [DebuggerStepThrough] + [DebuggerHidden] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public override object? InvokeMember( + string name, BindingFlags bindingFlags, Binder? binder, object? target, + object?[]? providedArgs, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParams) + { + const BindingFlags MemberBindingMask = (BindingFlags)0x000000FF; + const BindingFlags InvocationMask = (BindingFlags)0x0000FF00; + const BindingFlags BinderGetSetField = BindingFlags.GetField | BindingFlags.SetField; + const BindingFlags BinderGetSetProperty = BindingFlags.GetProperty | BindingFlags.SetProperty; + const BindingFlags BinderNonCreateInstance = BindingFlags.InvokeMethod | BinderGetSetField | BinderGetSetProperty; + const BindingFlags BinderNonFieldGetSet = (BindingFlags)0x00FFF300; + + if (IsGenericParameter) + throw new InvalidOperationException(SR.Arg_GenericParameter); + + if ((bindingFlags & InvocationMask) == 0) + // "Must specify binding flags describing the invoke operation required." + throw new ArgumentException(SR.Arg_NoAccessSpec, nameof(bindingFlags)); + + // Provide a default binding mask if none is provided + if ((bindingFlags & MemberBindingMask) == 0) + { + bindingFlags |= BindingFlags.Instance | BindingFlags.Public; + + if ((bindingFlags & BindingFlags.CreateInstance) == 0) + bindingFlags |= BindingFlags.Static; + } + + // There must not be more named parameters than provided arguments + if (namedParams != null) + { + if (providedArgs != null) + { + if (namedParams.Length > providedArgs.Length) + throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); + } + else + { + if (namedParams.Length != 0) + throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); + } + } + +#if FEATURE_COMINTEROP + if (target != null && target.GetType().IsCOMObject) + { + const BindingFlags ClassicBindingMask = + BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty | + BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty; + + if ((bindingFlags & ClassicBindingMask) == 0) + throw new ArgumentException(SR.Arg_COMAccess, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.GetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0) + throw new ArgumentException(SR.Arg_PropSetGet, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.InvokeMethod) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0) + throw new ArgumentException(SR.Arg_PropSetInvoke, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.SetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.SetProperty) != 0) + throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.PutDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutDispProperty) != 0) + throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.PutRefDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutRefDispProperty) != 0) + throw new ArgumentException(SR.Arg_COMPropSetPut, nameof(bindingFlags)); + + if (name == null) + throw new ArgumentNullException(nameof(name)); + + bool[]? isByRef = modifiers?[0].IsByRefArray; + + // pass LCID_ENGLISH_US if no explicit culture is specified to match the behavior of VB + int lcid = (culture == null ? 0x0409 : culture.LCID); + + // If a request to not wrap exceptions was made, we will unwrap + // the TargetInvocationException since that is what will be thrown. + bool unwrapExceptions = (bindingFlags & BindingFlags.DoNotWrapExceptions) != 0; + try + { + return InvokeDispMethod(name, bindingFlags, target, providedArgs, isByRef, lcid, namedParams); + } + catch (TargetInvocationException e) when (unwrapExceptions) + { + // For target invocation exceptions, we need to unwrap the inner exception and + // re-throw it. + throw e.InnerException!; + } + } +#endif // FEATURE_COMINTEROP + + if (namedParams != null && Array.IndexOf(namedParams, null!) != -1) + throw new ArgumentException(SR.Arg_NamedParamNull, nameof(namedParams)); + + int argCnt = (providedArgs != null) ? providedArgs.Length : 0; + + binder ??= DefaultBinder; + + // Delegate to Activator.CreateInstance + if ((bindingFlags & BindingFlags.CreateInstance) != 0) + { + if ((bindingFlags & BindingFlags.CreateInstance) != 0 && (bindingFlags & BinderNonCreateInstance) != 0) + // "Can not specify both CreateInstance and another access type." + throw new ArgumentException(SR.Arg_CreatInstAccess, nameof(bindingFlags)); + + return Activator.CreateInstance(this, bindingFlags, binder, providedArgs, culture); + } + + // PutDispProperty and\or PutRefDispProperty ==> SetProperty. + if ((bindingFlags & (BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty)) != 0) + bindingFlags |= BindingFlags.SetProperty; + + if (name == null) + throw new ArgumentNullException(nameof(name)); + + if (name.Length == 0 || name.Equals("[DISPID=0]")) + { + // in InvokeMember we always pretend there is a default member if none is provided and we make it ToString + name = GetDefaultMemberName()! ?? "ToString"; + } + + // GetField or SetField + bool IsGetField = (bindingFlags & BindingFlags.GetField) != 0; + bool IsSetField = (bindingFlags & BindingFlags.SetField) != 0; + + if (IsGetField || IsSetField) + { + if (IsGetField) + { + if (IsSetField) + throw new ArgumentException(SR.Arg_FldSetGet, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.SetProperty) != 0) + throw new ArgumentException(SR.Arg_FldGetPropSet, nameof(bindingFlags)); + } + else + { + Debug.Assert(IsSetField); + + if (providedArgs == null) + throw new ArgumentNullException(nameof(providedArgs)); + + if ((bindingFlags & BindingFlags.GetProperty) != 0) + throw new ArgumentException(SR.Arg_FldSetPropGet, nameof(bindingFlags)); + + if ((bindingFlags & BindingFlags.InvokeMethod) != 0) + throw new ArgumentException(SR.Arg_FldSetInvoke, nameof(bindingFlags)); + } + + // Lookup Field + FieldInfo? selFld = null; + FieldInfo[]? flds = GetMember(name, MemberTypes.Field, bindingFlags) as FieldInfo[]; + + Debug.Assert(flds != null); + + if (flds.Length == 1) + { + selFld = flds[0]; + } + else if (flds.Length > 0) + { + selFld = binder.BindToField(bindingFlags, flds, IsGetField ? Empty.Value : providedArgs![0]!, culture); + } + + if (selFld != null) + { + // Invocation on a field + if (selFld.FieldType.IsArray || ReferenceEquals(selFld.FieldType, typeof(Array))) + { + // Invocation of an array Field + int idxCnt; + if ((bindingFlags & BindingFlags.GetField) != 0) + { + idxCnt = argCnt; + } + else + { + idxCnt = argCnt - 1; + } + + if (idxCnt > 0) + { + // Verify that all of the index values are ints + int[] idx = new int[idxCnt]; + for (int i = 0; i < idxCnt; i++) + { + try + { + idx[i] = ((IConvertible)providedArgs![i]!).ToInt32(null); + } + catch (InvalidCastException) + { + throw new ArgumentException(SR.Arg_IndexMustBeInt); + } + } + + // Set or get the value... + Array a = (Array)selFld.GetValue(target)!; + + // Set or get the value in the array + if ((bindingFlags & BindingFlags.GetField) != 0) + { + return a.GetValue(idx); + } + else + { + a.SetValue(providedArgs![idxCnt], idx); + return null; + } + } + } + + if (IsGetField) + { + if (argCnt != 0) + throw new ArgumentException(SR.Arg_FldGetArgErr, nameof(bindingFlags)); + + return selFld.GetValue(target); + } + else + { + if (argCnt != 1) + throw new ArgumentException(SR.Arg_FldSetArgErr, nameof(bindingFlags)); + + selFld.SetValue(target, providedArgs![0], bindingFlags, binder, culture); + return null; + } + } + + if ((bindingFlags & BinderNonFieldGetSet) == 0) + throw new MissingFieldException(FullName, name); + } + + // @Legacy - This is RTM behavior + bool isGetProperty = (bindingFlags & BindingFlags.GetProperty) != 0; + bool isSetProperty = (bindingFlags & BindingFlags.SetProperty) != 0; + + if (isGetProperty || isSetProperty) + { + if (isGetProperty) + { + Debug.Assert(!IsSetField); + + if (isSetProperty) + throw new ArgumentException(SR.Arg_PropSetGet, nameof(bindingFlags)); + } + else + { + Debug.Assert(isSetProperty); + + Debug.Assert(!IsGetField); + + if ((bindingFlags & BindingFlags.InvokeMethod) != 0) + throw new ArgumentException(SR.Arg_PropSetInvoke, nameof(bindingFlags)); + } + } + + MethodInfo[]? finalists = null; + MethodInfo? finalist = null; + + if ((bindingFlags & BindingFlags.InvokeMethod) != 0) + { + // Lookup Methods + MethodInfo[] semiFinalists = (GetMember(name, MemberTypes.Method, bindingFlags) as MethodInfo[])!; + List? results = null; + + for (int i = 0; i < semiFinalists.Length; i++) + { + MethodInfo semiFinalist = semiFinalists[i]; + Debug.Assert(semiFinalist != null); + + if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) + continue; + + if (finalist == null) + { + finalist = semiFinalist; + } + else + { + results ??= new List(semiFinalists.Length) { finalist }; + results.Add(semiFinalist); + } + } + + if (results != null) + { + Debug.Assert(results.Count > 1); + finalists = results.ToArray(); + } + } + + Debug.Assert(finalists == null || finalist != null); + + // BindingFlags.GetProperty or BindingFlags.SetProperty + if (finalist == null && isGetProperty || isSetProperty) + { + // Lookup Property + PropertyInfo[] semiFinalists = (GetMember(name, MemberTypes.Property, bindingFlags) as PropertyInfo[])!; + List? results = null; + + for (int i = 0; i < semiFinalists.Length; i++) + { + MethodInfo? semiFinalist = null; + + if (isSetProperty) + { + semiFinalist = semiFinalists[i].GetSetMethod(true); + } + else + { + semiFinalist = semiFinalists[i].GetGetMethod(true); + } + + if (semiFinalist == null) + continue; + + if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) + continue; + + if (finalist == null) + { + finalist = semiFinalist; + } + else + { + results ??= new List(semiFinalists.Length) { finalist }; + results.Add(semiFinalist); + } + } + + if (results != null) + { + Debug.Assert(results.Count > 1); + finalists = results.ToArray(); + } + } + + if (finalist != null) + { + // Invoke + if (finalists == null && + argCnt == 0 && + finalist.GetParametersNoCopy().Length == 0 && + (bindingFlags & BindingFlags.OptionalParamBinding) == 0) + { + return finalist.Invoke(target, bindingFlags, binder, providedArgs, culture); + } + + finalists ??= new MethodInfo[] { finalist }; + providedArgs ??= Array.Empty(); + object? state = null; + MethodBase? invokeMethod = null; + + try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs!, modifiers, culture, namedParams, out state); } + catch (MissingMethodException) { } + + if (invokeMethod == null) + throw new MissingMethodException(FullName, name); + + object? result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); + + if (state != null) + binder.ReorderArgumentArray(ref providedArgs, state); + + return result; + } + + throw new MissingMethodException(FullName, name); + } + private RuntimeType? GetBaseType() { if (IsInterface) @@ -409,5 +785,30 @@ namespace System return RuntimeTypeHandle.GetBaseType(this); } + + private static void ThrowIfTypeNeverValidGenericArgument(RuntimeType type) + { + if (type.IsPointer || type.IsByRef || type == typeof(void)) + throw new ArgumentException( + SR.Format(SR.Argument_NeverValidGenericArgument, type)); + } + + internal static void SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParamters) + { + if (genericArguments == null) + throw new ArgumentNullException(); + + for (int i = 0; i < genericArguments.Length; i++) + { + if (genericArguments[i] == null) + throw new ArgumentNullException(); + + ThrowIfTypeNeverValidGenericArgument(genericArguments[i]); + } + + if (genericArguments.Length != genericParamters.Length) + throw new ArgumentException( + SR.Format(SR.Argument_NotEnoughGenArguments, genericArguments.Length, genericParamters.Length)); + } } } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index a703fc8..bb71ef1 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -163,31 +163,6 @@ namespace System typeName, throwOnError, ignoreCase, reflectionOnly, ref stackMark, false); } - private static void ThrowIfTypeNeverValidGenericArgument(RuntimeType type) - { - if (type.IsPointer || type.IsByRef || type == typeof(void)) - throw new ArgumentException( - SR.Format(SR.Argument_NeverValidGenericArgument, type)); - } - - internal static void SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParamters) - { - if (genericArguments == null) - throw new ArgumentNullException(); - - for (int i = 0; i < genericArguments.Length; i++) - { - if (genericArguments[i] == null) - throw new ArgumentNullException(); - - ThrowIfTypeNeverValidGenericArgument(genericArguments[i]); - } - - if (genericArguments.Length != genericParamters.Length) - throw new ArgumentException( - SR.Format(SR.Argument_NotEnoughGenArguments, genericArguments.Length, genericParamters.Length)); - } - private static void SplitName(string? fullname, out string? name, out string? ns) { name = null; @@ -1270,406 +1245,6 @@ namespace System #endregion - #region Invoke Member - private const BindingFlags MemberBindingMask = (BindingFlags)0x000000FF; - private const BindingFlags InvocationMask = (BindingFlags)0x0000FF00; - private const BindingFlags BinderNonCreateInstance = BindingFlags.InvokeMethod | BinderGetSetField | BinderGetSetProperty; - private const BindingFlags BinderGetSetProperty = BindingFlags.GetProperty | BindingFlags.SetProperty; - private const BindingFlags BinderGetSetField = BindingFlags.GetField | BindingFlags.SetField; - private const BindingFlags BinderNonFieldGetSet = (BindingFlags)0x00FFF300; - - [DebuggerStepThroughAttribute] - [Diagnostics.DebuggerHidden] - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public override object? InvokeMember( - string name, BindingFlags bindingFlags, Binder? binder, object? target, - object?[]? providedArgs, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParams) - { - if (IsGenericParameter) - throw new InvalidOperationException(SR.Arg_GenericParameter); - - #region Preconditions - if ((bindingFlags & InvocationMask) == 0) - // "Must specify binding flags describing the invoke operation required." - throw new ArgumentException(SR.Arg_NoAccessSpec, nameof(bindingFlags)); - - // Provide a default binding mask if none is provided - if ((bindingFlags & MemberBindingMask) == 0) - { - bindingFlags |= BindingFlags.Instance | BindingFlags.Public; - - if ((bindingFlags & BindingFlags.CreateInstance) == 0) - bindingFlags |= BindingFlags.Static; - } - - // There must not be more named parameters than provided arguments - if (namedParams != null) - { - if (providedArgs != null) - { - if (namedParams.Length > providedArgs.Length) - // "Named parameter array can not be bigger than argument array." - throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); - } - else - { - if (namedParams.Length != 0) - // "Named parameter array can not be bigger than argument array." - throw new ArgumentException(SR.Arg_NamedParamTooBig, nameof(namedParams)); - } - } - #endregion - - #region Check that any named paramters are not null - if (namedParams != null && Array.IndexOf(namedParams, null) != -1) - // "Named parameter value must not be null." - throw new ArgumentException(SR.Arg_NamedParamNull, nameof(namedParams)); - #endregion - - int argCnt = (providedArgs != null) ? providedArgs.Length : 0; - - #region Get a Binder - if (binder == null) - binder = DefaultBinder; - - #endregion - - #region Delegate to Activator.CreateInstance - if ((bindingFlags & BindingFlags.CreateInstance) != 0) - { - if ((bindingFlags & BindingFlags.CreateInstance) != 0 && (bindingFlags & BinderNonCreateInstance) != 0) - // "Can not specify both CreateInstance and another access type." - throw new ArgumentException(SR.Arg_CreatInstAccess, nameof(bindingFlags)); - - return Activator.CreateInstance(this, bindingFlags, binder, providedArgs, culture); - } - #endregion - - // PutDispProperty and\or PutRefDispProperty ==> SetProperty. - if ((bindingFlags & (BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty)) != 0) - bindingFlags |= BindingFlags.SetProperty; - - #region Name - if (name == null) - throw new ArgumentNullException(nameof(name)); - - if (name.Length == 0 || name.Equals(@"[DISPID=0]")) - { - name = GetDefaultMemberName() ?? "ToString"; // in InvokeMember we always pretend there is a default member if none is provided and we make it ToString - } - #endregion - - #region GetField or SetField - bool IsGetField = (bindingFlags & BindingFlags.GetField) != 0; - bool IsSetField = (bindingFlags & BindingFlags.SetField) != 0; - - if (IsGetField || IsSetField) - { - #region Preconditions - if (IsGetField) - { - if (IsSetField) - // "Can not specify both Get and Set on a field." - throw new ArgumentException(SR.Arg_FldSetGet, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.SetProperty) != 0) - // "Can not specify both GetField and SetProperty." - throw new ArgumentException(SR.Arg_FldGetPropSet, nameof(bindingFlags)); - } - else - { - Debug.Assert(IsSetField); - - if (providedArgs == null) - throw new ArgumentNullException(nameof(providedArgs)); - - if ((bindingFlags & BindingFlags.GetProperty) != 0) - // "Can not specify both SetField and GetProperty." - throw new ArgumentException(SR.Arg_FldSetPropGet, nameof(bindingFlags)); - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - // "Can not specify Set on a Field and Invoke on a method." - throw new ArgumentException(SR.Arg_FldSetInvoke, nameof(bindingFlags)); - } - #endregion - - #region Lookup Field - FieldInfo? selFld = null; - FieldInfo[]? flds = GetMember(name, MemberTypes.Field, bindingFlags) as FieldInfo[]; - - Debug.Assert(flds != null); - - if (flds.Length == 1) - { - selFld = flds[0]; - } - else if (flds.Length > 0) - { - selFld = binder.BindToField(bindingFlags, flds, IsGetField ? Empty.Value : providedArgs![0]!, culture); - } - #endregion - - if (selFld != null) - { - #region Invocation on a field - if (selFld.FieldType.IsArray || ReferenceEquals(selFld.FieldType, typeof(System.Array))) - { - #region Invocation of an array Field - int idxCnt; - - if ((bindingFlags & BindingFlags.GetField) != 0) - { - idxCnt = argCnt; - } - else - { - idxCnt = argCnt - 1; - } - - if (idxCnt > 0) - { - // Verify that all of the index values are ints - int[] idx = new int[idxCnt]; - for (int i = 0; i < idxCnt; i++) - { - try - { - idx[i] = ((IConvertible)providedArgs![i]!).ToInt32(null); - } - catch (InvalidCastException) - { - throw new ArgumentException(SR.Arg_IndexMustBeInt); - } - } - - // Set or get the value... - Array a = (Array)selFld.GetValue(target)!; - - // Set or get the value in the array - if ((bindingFlags & BindingFlags.GetField) != 0) - { - return a.GetValue(idx); - } - else - { - a.SetValue(providedArgs![idxCnt], idx); - return null; - } - } - #endregion - } - - if (IsGetField) - { - #region Get the field value - if (argCnt != 0) - throw new ArgumentException(SR.Arg_FldGetArgErr, nameof(bindingFlags)); - - return selFld.GetValue(target); - #endregion - } - else - { - #region Set the field Value - if (argCnt != 1) - throw new ArgumentException(SR.Arg_FldSetArgErr, nameof(bindingFlags)); - - selFld.SetValue(target, providedArgs![0], bindingFlags, binder, culture); - - return null; - #endregion - } - #endregion - } - - if ((bindingFlags & BinderNonFieldGetSet) == 0) - throw new MissingFieldException(FullName, name); - } - #endregion - - #region Caching Logic - /* - bool useCache = false; - - // Note that when we add something to the cache, we are careful to ensure - // that the actual providedArgs matches the parameters of the method. Otherwise, - // some default argument processing has occurred. We don't want anyone - // else with the same (insufficient) number of actual arguments to get a - // cache hit because then they would bypass the default argument processing - // and the invocation would fail. - if (bDefaultBinder && namedParams == null && argCnt < 6) - useCache = true; - - if (useCache) - { - MethodBase invokeMethod = GetMethodFromCache (name, bindingFlags, argCnt, providedArgs); - - if (invokeMethod != null) - return ((MethodInfo) invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); - } - */ - #endregion - - #region Property PreConditions - // @Legacy - This is RTM behavior - bool isGetProperty = (bindingFlags & BindingFlags.GetProperty) != 0; - bool isSetProperty = (bindingFlags & BindingFlags.SetProperty) != 0; - - if (isGetProperty || isSetProperty) - { - #region Preconditions - if (isGetProperty) - { - Debug.Assert(!IsSetField); - - if (isSetProperty) - throw new ArgumentException(SR.Arg_PropSetGet, nameof(bindingFlags)); - } - else - { - Debug.Assert(isSetProperty); - - Debug.Assert(!IsGetField); - - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - throw new ArgumentException(SR.Arg_PropSetInvoke, nameof(bindingFlags)); - } - #endregion - } - #endregion - - MethodInfo[]? finalists = null; - MethodInfo? finalist = null; - - #region BindingFlags.InvokeMethod - if ((bindingFlags & BindingFlags.InvokeMethod) != 0) - { - #region Lookup Methods - MethodInfo[] semiFinalists = (GetMember(name, MemberTypes.Method, bindingFlags) as MethodInfo[])!; - List? results = null; - - for (int i = 0; i < semiFinalists.Length; i++) - { - MethodInfo semiFinalist = semiFinalists[i]; - Debug.Assert(semiFinalist != null); - - if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) - continue; - - if (finalist == null) - { - finalist = semiFinalist; - } - else - { - results ??= new List(semiFinalists.Length) { finalist }; - results.Add(semiFinalist); - } - } - - if (results != null) - { - Debug.Assert(results.Count > 1); - finalists = new MethodInfo[results.Count]; - results.CopyTo(finalists); - } - #endregion - } - #endregion - - Debug.Assert(finalists == null || finalist != null); - - #region BindingFlags.GetProperty or BindingFlags.SetProperty - if (finalist == null && isGetProperty || isSetProperty) - { - #region Lookup Property - PropertyInfo[] semiFinalists = (GetMember(name, MemberTypes.Property, bindingFlags) as PropertyInfo[])!; - List? results = null; - - for (int i = 0; i < semiFinalists.Length; i++) - { - MethodInfo? semiFinalist = null; - - if (isSetProperty) - { - semiFinalist = semiFinalists[i].GetSetMethod(true); - } - else - { - semiFinalist = semiFinalists[i].GetGetMethod(true); - } - - if (semiFinalist == null) - continue; - - if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt])) - continue; - - if (finalist == null) - { - finalist = semiFinalist; - } - else - { - results ??= new List(semiFinalists.Length) { finalist }; - results.Add(semiFinalist); - } - } - - if (results != null) - { - Debug.Assert(results.Count > 1); - finalists = new MethodInfo[results.Count]; - results.CopyTo(finalists); - } - #endregion - } - #endregion - - if (finalist != null) - { - #region Invoke - if (finalists == null && - argCnt == 0 && - finalist.GetParametersNoCopy().Length == 0 && - (bindingFlags & BindingFlags.OptionalParamBinding) == 0) - { - //if (useCache && argCnt == props[0].GetParameters().Length) - // AddMethodToCache(name, bindingFlags, argCnt, providedArgs, props[0]); - - return finalist.Invoke(target, bindingFlags, binder, providedArgs, culture); - } - - finalists ??= new MethodInfo[] { finalist }; - providedArgs ??= Array.Empty(); - - object? state = null; - - - MethodBase? invokeMethod = null; - - try { invokeMethod = binder.BindToMethod(bindingFlags, finalists, ref providedArgs, modifiers, culture, namedParams, out state); } - catch (MissingMethodException) { } - - if (invokeMethod == null) - throw new MissingMethodException(FullName, name); - - //if (useCache && argCnt == invokeMethod.GetParameters().Length) - // AddMethodToCache(name, bindingFlags, argCnt, providedArgs, invokeMethod); - - object? result = ((MethodInfo)invokeMethod).Invoke(target, bindingFlags, binder, providedArgs, culture); - - if (state != null) - binder.ReorderArgumentArray(ref providedArgs, state); - - return result; - #endregion - } - - throw new MissingMethodException(FullName, name); - } - #endregion - public static bool operator ==(RuntimeType? left, RuntimeType? right) { return ReferenceEquals(left, right); -- 2.7.4