diff options
author | Atsushi Kanamori <AtsushiKan@users.noreply.github.com> | 2016-09-19 15:50:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-19 15:50:02 +0300 |
commit | 74c20f7d75ab9a51338175e9a828a9cbd62228d2 (patch) | |
tree | a7b78ad5116b08932b6f12fc36a9714456977d87 | |
parent | 3128685e6209f77fef2f0aac9ef8db33038c8ecf (diff) | |
parent | aaf835b53b42c1e74a2aa29d463f1839f272af9a (diff) |
Merge pull request #1866 from AtsushiKan/prep
Add some coreclr files for history purposes.
6 files changed, 1550 insertions, 30 deletions
diff --git a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj index 29e0976ad..bf48e6f40 100644 --- a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj +++ b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj @@ -44,7 +44,7 @@ <Compile Include="System\Reflection\Runtime\Assemblies\RuntimeAssembly.GetTypeCore.CaseInsensitive.cs" /> <Compile Include="System\Reflection\Runtime\Assemblies\RuntimeAssembly.GetTypeCore.CaseSensitive.cs" /> <Compile Include="System\Reflection\Runtime\Assemblies\RuntimeAssemblyName.cs" /> - <Compile Include="System\Reflection\Runtime\BindingFlagSupport\DefaultBinder.cs" /> + <Compile Include="System\Reflection\Runtime\BindingFlagSupport\DefaultBinder.Old.cs" /> <Compile Include="System\Reflection\Runtime\BindingFlagSupport\DefaultBinder.LimitedBinder.cs" /> <Compile Include="System\Reflection\Runtime\BindingFlagSupport\MemberEnumerator.cs" /> <Compile Include="System\Reflection\Runtime\BindingFlagSupport\MemberPolicies.cs" /> diff --git a/src/System.Private.Reflection.Core/src/System/Empty.cs b/src/System.Private.Reflection.Core/src/System/Empty.cs new file mode 100644 index 000000000..f7e748601 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Empty.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//////////////////////////////////////////////////////////////////////////////// +// Empty +// This class represents an empty variant +//////////////////////////////////////////////////////////////////////////////// +using System.Diagnostics.Contracts; +namespace System { + + using System; + using System.Runtime.Remoting; + using System.Runtime.Serialization; + + [Serializable] + internal sealed class Empty : ISerializable + { + private Empty() { + } + + public static readonly Empty Value = new Empty(); + + public override String ToString() + { + return String.Empty; + } + + [System.Security.SecurityCritical] // auto-generated + public void GetObjectData(SerializationInfo info, StreamingContext context) { + if (info==null) { + throw new ArgumentNullException("info"); + } + Contract.EndContractBlock(); + UnitySerializationHolder.GetUnitySerializationInfo(info, UnitySerializationHolder.EmptyUnity, null, null); + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.Old.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.Old.cs new file mode 100644 index 000000000..a3d7776b1 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.Old.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Globalization; + +using Internal.LowLevelLinq; + +namespace System.Reflection.Runtime.BindingFlagSupport +{ + internal sealed partial class DefaultBinder : Binder + { + public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) + { + if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null && culture == null && names == null) + throw new NotImplementedException(); + state = null; + return LimitedBinder.BindToMethod(match, ref args); + } + + public sealed override object ChangeType(object value, Type type, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public sealed override void ReorderArgumentArray(ref object[] args, object state) + { + throw new NotImplementedException(); + } + + public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers) + { + if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null) + throw new NotImplementedException(); + + return LimitedBinder.SelectMethod(match, types); + } + + public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) + { + if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null) + throw new NotImplementedException(); + + PropertyInfo[] memberArray = match.ToArray(); + + if (memberArray.Length == 0) + return null; + + return LimitedBinder.SelectProperty(memberArray, returnType, indexes); + } + + private const BindingFlags SupportedBindingFlags = BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance; + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.cs index a3d7776b1..405055e84 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/DefaultBinder.cs @@ -2,58 +2,1167 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Globalization; +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// This class represents the Default COM+ binder. +// +// +namespace System { -using Internal.LowLevelLinq; - -namespace System.Reflection.Runtime.BindingFlagSupport -{ - internal sealed partial class DefaultBinder : Binder + using System; + using System.Reflection; + using System.Runtime.CompilerServices; + using System.Runtime.Versioning; + using System.Diagnostics.Contracts; + using CultureInfo = System.Globalization.CultureInfo; + //Marked serializable even though it has no state. + [Serializable] + internal class DefaultBinder : Binder { - public sealed override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) + // This method is passed a set of methods and must choose the best + // fit. The methods all have the same number of arguments and the object + // array args. On exit, this method will choice the best fit method + // and coerce the args to match that method. By match, we mean all primitive + // arguments are exact matchs and all object arguments are exact or subclasses + // of the target. If the target OR is an interface, the object must implement + // that interface. There are a couple of exceptions + // thrown when a method cannot be returned. If no method matchs the args and + // ArgumentException is thrown. If multiple methods match the args then + // an AmbiguousMatchException is thrown. + // + // The most specific match will be selected. + // + [System.Security.SecuritySafeCritical] // auto-generated + public override MethodBase BindToMethod( + BindingFlags bindingAttr, MethodBase[] match, ref Object[] args, + ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, out Object state) + { + if (match == null || match.Length == 0) + throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match"); + Contract.EndContractBlock(); + + MethodBase[] candidates = (MethodBase[]) match.Clone(); + + int i; + int j; + + state = null; + + #region Map named parameters to candidate parameter postions + // We are creating an paramOrder array to act as a mapping + // between the order of the args and the actual order of the + // parameters in the method. This order may differ because + // named parameters (names) may change the order. If names + // is not provided, then we assume the default mapping (0,1,...) + int[][] paramOrder = new int[candidates.Length][]; + + for (i = 0; i < candidates.Length; i++) + { + ParameterInfo[] par = candidates[i].GetParametersNoCopy(); + + // args.Length + 1 takes into account the possibility of a last paramArray that can be omitted + paramOrder[i] = new int[(par.Length > args.Length) ? par.Length : args.Length]; + + if (names == null) + { + // Default mapping + for (j = 0; j < args.Length; j++) + paramOrder[i][j] = j; + } + else + { + // Named parameters, reorder the mapping. If CreateParamOrder fails, it means that the method + // doesn't have a name that matchs one of the named parameters so we don't consider it any further. + if (!CreateParamOrder(paramOrder[i], par, names)) + candidates[i] = null; + } + } + #endregion + + Type[] paramArrayTypes = new Type[candidates.Length]; + + Type[] argTypes = new Type[args.Length]; + + #region Cache the type of the provided arguments + // object that contain a null are treated as if they were typeless (but match either object + // references or value classes). We mark this condition by placing a null in the argTypes array. + for (i = 0; i < args.Length; i++) + { + if (args[i] != null) + { + argTypes[i] = args[i].GetType(); + } + } + #endregion + + + // Find the method that matches... + int CurIdx = 0; + bool defaultValueBinding = ((bindingAttr & BindingFlags.OptionalParamBinding) != 0); + + Type paramArrayType = null; + + #region Filter methods by parameter count and type + for (i = 0; i < candidates.Length; i++) + { + paramArrayType = null; + + // If we have named parameters then we may have a hole in the candidates array. + if (candidates[i] == null) + continue; + + // Validate the parameters. + ParameterInfo[] par = candidates[i].GetParametersNoCopy(); + + #region Match method by parameter count + if (par.Length == 0) + { + #region No formal parameters + if (args.Length != 0) + { + if ((candidates[i].CallingConvention & CallingConventions.VarArgs) == 0) + continue; + } + + // This is a valid routine so we move it up the candidates list. + paramOrder[CurIdx] = paramOrder[i]; + candidates[CurIdx++] = candidates[i]; + + continue; + #endregion + } + else if (par.Length > args.Length) + { + #region Shortage of provided parameters + // If the number of parameters is greater than the number of args then + // we are in the situation were we may be using default values. + for (j = args.Length; j < par.Length - 1; j++) + { + if (par[j].DefaultValue == System.DBNull.Value) + break; + } + + if (j != par.Length - 1) + continue; + + if (par[j].DefaultValue == System.DBNull.Value) + { + if (!par[j].ParameterType.IsArray) + continue; + + if (!par[j].IsDefined(typeof(ParamArrayAttribute), true)) + continue; + + paramArrayType = par[j].ParameterType.GetElementType(); + } + #endregion + } + else if (par.Length < args.Length) + { + #region Excess provided parameters + // test for the ParamArray case + int lastArgPos = par.Length - 1; + + if (!par[lastArgPos].ParameterType.IsArray) + continue; + + if (!par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true)) + continue; + + if (paramOrder[i][lastArgPos] != lastArgPos) + continue; + + paramArrayType = par[lastArgPos].ParameterType.GetElementType(); + #endregion + } + else + { + #region Test for paramArray, save paramArray type + int lastArgPos = par.Length - 1; + + if (par[lastArgPos].ParameterType.IsArray + && par[lastArgPos].IsDefined(typeof(ParamArrayAttribute), true) + && paramOrder[i][lastArgPos] == lastArgPos) + { + if (!par[lastArgPos].ParameterType.IsAssignableFrom(argTypes[lastArgPos])) + paramArrayType = par[lastArgPos].ParameterType.GetElementType(); + } + #endregion + } + #endregion + + Type pCls = null; + int argsToCheck = (paramArrayType != null) ? par.Length - 1 : args.Length; + + #region Match method by parameter type + for (j = 0; j < argsToCheck; j++) + { + #region Classic argument coersion checks + // get the formal type + pCls = par[j].ParameterType; + + if (pCls.IsByRef) + pCls = pCls.GetElementType(); + + // the type is the same + if (pCls == argTypes[paramOrder[i][j]]) + continue; + + // a default value is available + if (defaultValueBinding && args[paramOrder[i][j]] == Type.Missing) + continue; + + // the argument was null, so it matches with everything + if (args[paramOrder[i][j]] == null) + continue; + + // the type is Object, so it will match everything + if (pCls == typeof(Object)) + continue; + + // now do a "classic" type check + if (pCls.IsPrimitive) + { + if (argTypes[paramOrder[i][j]] == null || !CanConvertPrimitiveObjectToType(args[paramOrder[i][j]],(RuntimeType)pCls)) + { + break; + } + } + else + { + if (argTypes[paramOrder[i][j]] == null) + continue; + + if (!pCls.IsAssignableFrom(argTypes[paramOrder[i][j]])) + { + if (argTypes[paramOrder[i][j]].IsCOMObject) + { + if (pCls.IsInstanceOfType(args[paramOrder[i][j]])) + continue; + } + break; + } + } + #endregion + } + + if (paramArrayType != null && j == par.Length - 1) + { + #region Check that excess arguments can be placed in the param array + for (; j < args.Length; j++) + { + if (paramArrayType.IsPrimitive) + { + if (argTypes[j] == null || !CanConvertPrimitiveObjectToType(args[j], (RuntimeType)paramArrayType)) + break; + } + else + { + if (argTypes[j] == null) + continue; + + if (!paramArrayType.IsAssignableFrom(argTypes[j])) + { + if (argTypes[j].IsCOMObject) + { + if (paramArrayType.IsInstanceOfType(args[j])) + continue; + } + + break; + } + } + } + #endregion + } + #endregion + + if (j == args.Length) + { + #region This is a valid routine so we move it up the candidates list + paramOrder[CurIdx] = paramOrder[i]; + paramArrayTypes[CurIdx] = paramArrayType; + candidates[CurIdx++] = candidates[i]; + #endregion + } + } + #endregion + + // If we didn't find a method + if (CurIdx == 0) + throw new MissingMethodException(Environment.GetResourceString("MissingMember")); + + if (CurIdx == 1) + { + #region Found only one method + if (names != null) + { + state = new BinderState((int[])paramOrder[0].Clone(), args.Length, paramArrayTypes[0] != null); + ReorderParams(paramOrder[0],args); + } + + // If the parameters and the args are not the same length or there is a paramArray + // then we need to create a argument array. + ParameterInfo[] parms = candidates[0].GetParametersNoCopy(); + + if (parms.Length == args.Length) + { + if (paramArrayTypes[0] != null) + { + Object[] objs = new Object[parms.Length]; + int lastPos = parms.Length - 1; + Array.Copy(args, 0, objs, 0, lastPos); + objs[lastPos] = Array.UnsafeCreateInstance(paramArrayTypes[0], 1); + ((Array)objs[lastPos]).SetValue(args[lastPos], 0); + args = objs; + } + } + else if (parms.Length > args.Length) + { + Object[] objs = new Object[parms.Length]; + + for (i=0;i<args.Length;i++) + objs[i] = args[i]; + + for (;i<parms.Length - 1;i++) + objs[i] = parms[i].DefaultValue; + + if (paramArrayTypes[0] != null) + objs[i] = Array.UnsafeCreateInstance(paramArrayTypes[0], 0); // create an empty array for the + + else + objs[i] = parms[i].DefaultValue; + + args = objs; + } + else + { + if ((candidates[0].CallingConvention & CallingConventions.VarArgs) == 0) + { + Object[] objs = new Object[parms.Length]; + int paramArrayPos = parms.Length - 1; + Array.Copy(args, 0, objs, 0, paramArrayPos); + objs[paramArrayPos] = Array.UnsafeCreateInstance(paramArrayTypes[0], args.Length - paramArrayPos); + Array.Copy(args, paramArrayPos, (System.Array)objs[paramArrayPos], 0, args.Length - paramArrayPos); + args = objs; + } + } + #endregion + + return candidates[0]; + } + + int currentMin = 0; + bool ambig = false; + for (i = 1; i < CurIdx; i++) + { + #region Walk all of the methods looking the most specific method to invoke + int newMin = FindMostSpecificMethod(candidates[currentMin], paramOrder[currentMin], paramArrayTypes[currentMin], + candidates[i], paramOrder[i], paramArrayTypes[i], argTypes, args); + + if (newMin == 0) + { + ambig = true; + } + else if (newMin == 2) + { + currentMin = i; + ambig = false; + } + #endregion + } + + if (ambig) + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + + // Reorder (if needed) + if (names != null) { + state = new BinderState((int[])paramOrder[currentMin].Clone(), args.Length, paramArrayTypes[currentMin] != null); + ReorderParams(paramOrder[currentMin], args); + } + + // If the parameters and the args are not the same length or there is a paramArray + // then we need to create a argument array. + ParameterInfo[] parameters = candidates[currentMin].GetParametersNoCopy(); + if (parameters.Length == args.Length) + { + if (paramArrayTypes[currentMin] != null) + { + Object[] objs = new Object[parameters.Length]; + int lastPos = parameters.Length - 1; + Array.Copy(args, 0, objs, 0, lastPos); + objs[lastPos] = Array.UnsafeCreateInstance(paramArrayTypes[currentMin], 1); + ((Array)objs[lastPos]).SetValue(args[lastPos], 0); + args = objs; + } + } + else if (parameters.Length > args.Length) + { + Object[] objs = new Object[parameters.Length]; + + for (i=0;i<args.Length;i++) + objs[i] = args[i]; + + for (;i<parameters.Length - 1;i++) + objs[i] = parameters[i].DefaultValue; + + if (paramArrayTypes[currentMin] != null) + { + objs[i] = Array.UnsafeCreateInstance(paramArrayTypes[currentMin], 0); + } + else + { + objs[i] = parameters[i].DefaultValue; + } + + args = objs; + } + else + { + if ((candidates[currentMin].CallingConvention & CallingConventions.VarArgs) == 0) + { + Object[] objs = new Object[parameters.Length]; + int paramArrayPos = parameters.Length - 1; + Array.Copy(args, 0, objs, 0, paramArrayPos); + objs[paramArrayPos] = Array.UnsafeCreateInstance(paramArrayTypes[currentMin], args.Length - paramArrayPos); + Array.Copy(args, paramArrayPos, (System.Array)objs[paramArrayPos], 0, args.Length - paramArrayPos); + args = objs; + } + } + + return candidates[currentMin]; + } + + + // Given a set of fields that match the base criteria, select a field. + // if value is null then we have no way to select a field + [System.Security.SecuritySafeCritical] // auto-generated + public override FieldInfo BindToField(BindingFlags bindingAttr,FieldInfo[] match, Object value,CultureInfo cultureInfo) { - throw new NotImplementedException(); + if (match == null) { + throw new ArgumentNullException("match"); + } + + int i; + // Find the method that match... + int CurIdx = 0; + + Type valueType = null; + + FieldInfo[] candidates = (FieldInfo[]) match.Clone(); + + // If we are a FieldSet, then use the value's type to disambiguate + if ((bindingAttr & BindingFlags.SetField) != 0) { + valueType = value.GetType(); + + for (i=0;i<candidates.Length;i++) { + Type pCls = candidates[i].FieldType; + if (pCls == valueType) { + candidates[CurIdx++] = candidates[i]; + continue; + } + if (value == Empty.Value) { + // the object passed in was null which would match any non primitive non value type + if (pCls.IsClass) { + candidates[CurIdx++] = candidates[i]; + continue; + } + } + if (pCls == typeof(Object)) { + candidates[CurIdx++] = candidates[i]; + continue; + } + if (pCls.IsPrimitive) { + if (CanConvertPrimitiveObjectToType(value,(RuntimeType)pCls)) { + candidates[CurIdx++] = candidates[i]; + continue; + } + } + else { + if (pCls.IsAssignableFrom(valueType)) { + candidates[CurIdx++] = candidates[i]; + continue; + } + } + } + if (CurIdx == 0) + throw new MissingFieldException(Environment.GetResourceString("MissingField")); + if (CurIdx == 1) + return candidates[0]; + } + + // Walk all of the methods looking the most specific method to invoke + int currentMin = 0; + bool ambig = false; + for (i=1;i<CurIdx;i++) { + int newMin = FindMostSpecificField(candidates[currentMin], candidates[i]); + if (newMin == 0) + ambig = true; + else { + if (newMin == 2) { + currentMin = i; + ambig = false; + } + } + } + if (ambig) + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + return candidates[currentMin]; } + + // Given a set of methods that match the base criteria, select a method based + // upon an array of types. This method should return null if no method matchs + // the criteria. + [System.Security.SecuritySafeCritical] // auto-generated + public override MethodBase SelectMethod(BindingFlags bindingAttr,MethodBase[] match,Type[] types,ParameterModifier[] modifiers) + { + int i; + int j; + + Type[] realTypes = new Type[types.Length]; + for (i=0;i<types.Length;i++) { + realTypes[i] = types[i].UnderlyingSystemType; + if (!(realTypes[i] is RuntimeType)) + throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"),"types"); + } + types = realTypes; + + // We don't automatically jump out on exact match. + if (match == null || match.Length == 0) + throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match"); - public sealed override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) + MethodBase[] candidates = (MethodBase[]) match.Clone(); + + // Find all the methods that can be described by the types parameter. + // Remove all of them that cannot. + int CurIdx = 0; + for (i=0;i<candidates.Length;i++) { + ParameterInfo[] par = candidates[i].GetParametersNoCopy(); + if (par.Length != types.Length) + continue; + for (j=0;j<types.Length;j++) { + Type pCls = par[j].ParameterType; + if (pCls == types[j]) + continue; + if (pCls == typeof(Object)) + continue; + if (pCls.IsPrimitive) { + if (!(types[j].UnderlyingSystemType is RuntimeType) || + !CanConvertPrimitive((RuntimeType)types[j].UnderlyingSystemType,(RuntimeType)pCls.UnderlyingSystemType)) + break; + } + else { + if (!pCls.IsAssignableFrom(types[j])) + break; + } + } + if (j == types.Length) + candidates[CurIdx++] = candidates[i]; + } + if (CurIdx == 0) + return null; + if (CurIdx == 1) + return candidates[0]; + + // Walk all of the methods looking the most specific method to invoke + int currentMin = 0; + bool ambig = false; + int[] paramOrder = new int[types.Length]; + for (i=0;i<types.Length;i++) + paramOrder[i] = i; + for (i=1;i<CurIdx;i++) { + int newMin = FindMostSpecificMethod(candidates[currentMin], paramOrder, null, candidates[i], paramOrder, null, types, null); + if (newMin == 0) + ambig = true; + else { + if (newMin == 2) { + currentMin = i; + ambig = false; + currentMin = i; + } + } + } + if (ambig) + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + return candidates[currentMin]; + } + + // Given a set of properties that match the base criteria, select one. + [System.Security.SecuritySafeCritical] // auto-generated + public override PropertyInfo SelectProperty(BindingFlags bindingAttr,PropertyInfo[] match,Type returnType, + Type[] indexes,ParameterModifier[] modifiers) { - if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null && culture == null && names == null) - throw new NotImplementedException(); - state = null; - return LimitedBinder.BindToMethod(match, ref args); + // Allow a null indexes array. But if it is not null, every element must be non-null as well. + if (indexes != null && !Contract.ForAll(indexes, delegate(Type t) { return t != null; })) + { + throw new ArgumentNullException("indexes"); + } + if (match == null || match.Length == 0) + throw new ArgumentException(Environment.GetResourceString("Arg_EmptyArray"), "match"); + Contract.EndContractBlock(); + + PropertyInfo[] candidates = (PropertyInfo[]) match.Clone(); + + int i,j = 0; + + // Find all the properties that can be described by type indexes parameter + int CurIdx = 0; + int indexesLength = (indexes != null) ? indexes.Length : 0; + for (i=0;i<candidates.Length;i++) { + + if (indexes != null) + { + ParameterInfo[] par = candidates[i].GetIndexParameters(); + if (par.Length != indexesLength) + continue; + + for (j=0;j<indexesLength;j++) { + Type pCls = par[j]. ParameterType; + + // If the classes exactly match continue + if (pCls == indexes[j]) + continue; + if (pCls == typeof(Object)) + continue; + + if (pCls.IsPrimitive) { + if (!(indexes[j].UnderlyingSystemType is RuntimeType) || + !CanConvertPrimitive((RuntimeType)indexes[j].UnderlyingSystemType,(RuntimeType)pCls.UnderlyingSystemType)) + break; + } + else { + if (!pCls.IsAssignableFrom(indexes[j])) + break; + } + } + } + + if (j == indexesLength) { + if (returnType != null) { + if (candidates[i].PropertyType.IsPrimitive) { + if (!(returnType.UnderlyingSystemType is RuntimeType) || + !CanConvertPrimitive((RuntimeType)returnType.UnderlyingSystemType,(RuntimeType)candidates[i].PropertyType.UnderlyingSystemType)) + continue; + } + else { + if (!candidates[i].PropertyType.IsAssignableFrom(returnType)) + continue; + } + } + candidates[CurIdx++] = candidates[i]; + } + } + if (CurIdx == 0) + return null; + if (CurIdx == 1) + return candidates[0]; + + // Walk all of the properties looking the most specific method to invoke + int currentMin = 0; + bool ambig = false; + int[] paramOrder = new int[indexesLength]; + for (i=0;i<indexesLength;i++) + paramOrder[i] = i; + for (i=1;i<CurIdx;i++) { + int newMin = FindMostSpecificType(candidates[currentMin].PropertyType, candidates[i].PropertyType,returnType); + if (newMin == 0 && indexes != null) + newMin = FindMostSpecific(candidates[currentMin].GetIndexParameters(), + paramOrder, + null, + candidates[i].GetIndexParameters(), + paramOrder, + null, + indexes, + null); + if (newMin == 0) + { + newMin = FindMostSpecificProperty(candidates[currentMin], candidates[i]); + if (newMin == 0) + ambig = true; + } + if (newMin == 2) { + ambig = false; + currentMin = i; + } + } + + if (ambig) + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + return candidates[currentMin]; } + + // ChangeType + // The default binder doesn't support any change type functionality. + // This is because the default is built into the low level invoke code. + public override Object ChangeType(Object value,Type type,CultureInfo cultureInfo) + { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_ChangeType")); + } + + public override void ReorderArgumentArray(ref Object[] args, Object state) + { + BinderState binderState = (BinderState)state; + ReorderParams(binderState.m_argsMap, args); + if (binderState.m_isParamArray) { + int paramArrayPos = args.Length - 1; + if (args.Length == binderState.m_originalSize) + args[paramArrayPos] = ((Object[])args[paramArrayPos])[0]; + else { + // must be args.Length < state.originalSize + Object[] newArgs = new Object[args.Length]; + Array.Copy(args, 0, newArgs, 0, paramArrayPos); + for (int i = paramArrayPos, j = 0; i < newArgs.Length; i++, j++) { + newArgs[i] = ((Object[])args[paramArrayPos])[j]; + } + args = newArgs; + } + } + else { + if (args.Length > binderState.m_originalSize) { + Object[] newArgs = new Object[binderState.m_originalSize]; + Array.Copy(args, 0, newArgs, 0, binderState.m_originalSize); + args = newArgs; + } + } + } + + // Return any exact bindings that may exist. (This method is not defined on the + // Binder and is used by RuntimeType.) + public static MethodBase ExactBinding(MethodBase[] match,Type[] types,ParameterModifier[] modifiers) + { + if (match==null) + throw new ArgumentNullException("match"); + Contract.EndContractBlock(); + MethodBase[] aExactMatches = new MethodBase[match.Length]; + int cExactMatches = 0; + + for (int i=0;i<match.Length;i++) { + ParameterInfo[] par = match[i].GetParametersNoCopy(); + if (par.Length == 0) { + continue; + } + int j; + for (j=0;j<types.Length;j++) { + Type pCls = par[j]. ParameterType; + + // If the classes exactly match continue + if (!pCls.Equals(types[j])) + break; + } + if (j < types.Length) + continue; + + // Add the exact match to the array of exact matches. + aExactMatches[cExactMatches] = match[i]; + cExactMatches++; + } + + if (cExactMatches == 0) + return null; + + if (cExactMatches == 1) + return aExactMatches[0]; + + return FindMostDerivedNewSlotMeth(aExactMatches, cExactMatches); + } + + // Return any exact bindings that may exist. (This method is not defined on the + // Binder and is used by RuntimeType.) + public static PropertyInfo ExactPropertyBinding(PropertyInfo[] match,Type returnType,Type[] types,ParameterModifier[] modifiers) + { + if (match==null) + throw new ArgumentNullException("match"); + Contract.EndContractBlock(); + + PropertyInfo bestMatch = null; + int typesLength = (types != null) ? types.Length : 0; + for (int i=0;i<match.Length;i++) { + ParameterInfo[] par = match[i].GetIndexParameters(); + int j; + for (j=0;j<typesLength;j++) { + Type pCls = par[j].ParameterType; + + // If the classes exactly match continue + if (pCls != types[j]) + break; + } + if (j < typesLength) + continue; + if (returnType != null && returnType != match[i].PropertyType) + continue; + + if (bestMatch != null) + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + + bestMatch = match[i]; + } + return bestMatch; + } + + private static int FindMostSpecific(ParameterInfo[] p1, int[] paramOrder1, Type paramArrayType1, + ParameterInfo[] p2, int[] paramOrder2, Type paramArrayType2, + Type[] types, Object[] args) + { + // A method using params is always less specific than one not using params + if (paramArrayType1 != null && paramArrayType2 == null) return 2; + if (paramArrayType2 != null && paramArrayType1 == null) return 1; + + // now either p1 and p2 both use params or neither does. + + bool p1Less = false; + bool p2Less = false; + + for (int i = 0; i < types.Length; i++) + { + if (args != null && args[i] == Type.Missing) + continue; + + Type c1, c2; + + // If a param array is present, then either + // the user re-ordered the parameters in which case + // the argument to the param array is either an array + // in which case the params is conceptually ignored and so paramArrayType1 == null + // or the argument to the param array is a single element + // in which case paramOrder[i] == p1.Length - 1 for that element + // or the user did not re-order the parameters in which case + // the paramOrder array could contain indexes larger than p.Length - 1 (see VSW 577286) + // so any index >= p.Length - 1 is being put in the param array + + if (paramArrayType1 != null && paramOrder1[i] >= p1.Length - 1) + c1 = paramArrayType1; + else + c1 = p1[paramOrder1[i]].ParameterType; + + if (paramArrayType2 != null && paramOrder2[i] >= p2.Length - 1) + c2 = paramArrayType2; + else + c2 = p2[paramOrder2[i]].ParameterType; + + if (c1 == c2) continue; + + switch (FindMostSpecificType(c1, c2, types[i])) { + case 0: return 0; + case 1: p1Less = true; break; + case 2: p2Less = true; break; + } + } + + // Two way p1Less and p2Less can be equal. All the arguments are the + // same they both equal false, otherwise there were things that both + // were the most specific type on.... + if (p1Less == p2Less) + { + // if we cannot tell which is a better match based on parameter types (p1Less == p2Less), + // let's see which one has the most matches without using the params array (the longer one wins). + if (!p1Less && args != null) + { + if (p1.Length > p2.Length) + { + return 1; + } + else if (p2.Length > p1.Length) + { + return 2; + } + } + + return 0; + } + else + { + return (p1Less == true) ? 1 : 2; + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + private static int FindMostSpecificType(Type c1, Type c2, Type t) + { + // If the two types are exact move on... + if (c1 == c2) + return 0; + + if (c1 == t) + return 1; + + if (c2 == t) + return 2; + + bool c1FromC2; + bool c2FromC1; + + if (c1.IsByRef || c2.IsByRef) + { + if (c1.IsByRef && c2.IsByRef) + { + c1 = c1.GetElementType(); + c2 = c2.GetElementType(); + } + else if (c1.IsByRef) + { + if (c1.GetElementType() == c2) + return 2; - public sealed override object ChangeType(object value, Type type, CultureInfo culture) + c1 = c1.GetElementType(); + } + else + { + if (c2.GetElementType() == c1) + return 1; + + c2 = c2.GetElementType(); + } + } + + + if (c1.IsPrimitive && c2.IsPrimitive) + { + c1FromC2 = CanConvertPrimitive((RuntimeType)c2, (RuntimeType)c1); + c2FromC1 = CanConvertPrimitive((RuntimeType)c1, (RuntimeType)c2); + } + else + { + c1FromC2 = c1.IsAssignableFrom(c2); + c2FromC1 = c2.IsAssignableFrom(c1); + } + + if (c1FromC2 == c2FromC1) + return 0; + + if (c1FromC2) + { + return 2; + } + else + { + return 1; + } + } + + private static int FindMostSpecificMethod(MethodBase m1, int[] paramOrder1, Type paramArrayType1, + MethodBase m2, int[] paramOrder2, Type paramArrayType2, + Type[] types, Object[] args) { - throw new NotImplementedException(); + // Find the most specific method based on the parameters. + int res = FindMostSpecific(m1.GetParametersNoCopy(), paramOrder1, paramArrayType1, + m2.GetParametersNoCopy(), paramOrder2, paramArrayType2, types, args); + + // If the match was not ambigous then return the result. + if (res != 0) + return res; + + // Check to see if the methods have the exact same name and signature. + if (CompareMethodSigAndName(m1, m2)) + { + // Determine the depth of the declaring types for both methods. + int hierarchyDepth1 = GetHierarchyDepth(m1.DeclaringType); + int hierarchyDepth2 = GetHierarchyDepth(m2.DeclaringType); + + // The most derived method is the most specific one. + if (hierarchyDepth1 == hierarchyDepth2) + { + return 0; + } + else if (hierarchyDepth1 < hierarchyDepth2) + { + return 2; + } + else + { + return 1; + } + } + + // The match is ambigous. + return 0; } - public sealed override void ReorderArgumentArray(ref object[] args, object state) + private static int FindMostSpecificField(FieldInfo cur1,FieldInfo cur2) { - throw new NotImplementedException(); + // Check to see if the fields have the same name. + if (cur1.Name == cur2.Name) + { + int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType); + int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType); + + if (hierarchyDepth1 == hierarchyDepth2) { + Contract.Assert(cur1.IsStatic != cur2.IsStatic, "hierarchyDepth1 == hierarchyDepth2"); + return 0; + } + else if (hierarchyDepth1 < hierarchyDepth2) + return 2; + else + return 1; + } + + // The match is ambigous. + return 0; } - public sealed override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers) + private static int FindMostSpecificProperty(PropertyInfo cur1,PropertyInfo cur2) { - if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null) - throw new NotImplementedException(); + // Check to see if the fields have the same name. + if (cur1.Name == cur2.Name) + { + int hierarchyDepth1 = GetHierarchyDepth(cur1.DeclaringType); + int hierarchyDepth2 = GetHierarchyDepth(cur2.DeclaringType); + + if (hierarchyDepth1 == hierarchyDepth2) { + return 0; + } + else if (hierarchyDepth1 < hierarchyDepth2) + return 2; + else + return 1; + } + + // The match is ambigous. + return 0; + } + + internal static bool CompareMethodSigAndName(MethodBase m1, MethodBase m2) + { + ParameterInfo[] params1 = m1.GetParametersNoCopy(); + ParameterInfo[] params2 = m2.GetParametersNoCopy(); + + if (params1.Length != params2.Length) + return false; + + int numParams = params1.Length; + for (int i = 0; i < numParams; i++) + { + if (params1[i].ParameterType != params2[i].ParameterType) + return false; + } - return LimitedBinder.SelectMethod(match, types); + return true; } - public sealed override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) + internal static int GetHierarchyDepth(Type t) { - if (!((bindingAttr & ~SupportedBindingFlags) == 0) && modifiers == null) - throw new NotImplementedException(); + int depth = 0; - PropertyInfo[] memberArray = match.ToArray(); + Type currentType = t; + do + { + depth++; + currentType = currentType.BaseType; + } while (currentType != null); - if (memberArray.Length == 0) - return null; + return depth; + } + + internal static MethodBase FindMostDerivedNewSlotMeth(MethodBase[] match, int cMatches) + { + int deepestHierarchy = 0; + MethodBase methWithDeepestHierarchy = null; + + for (int i = 0; i < cMatches; i++) + { + // Calculate the depth of the hierarchy of the declaring type of the + // current method. + int currentHierarchyDepth = GetHierarchyDepth(match[i].DeclaringType); + + // The two methods have the same name, signature, and hierarchy depth. + // This can only happen if at least one is vararg or generic. + if (currentHierarchyDepth == deepestHierarchy) + { + throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException")); + } + + // Check to see if this method is on the most derived class. + if (currentHierarchyDepth > deepestHierarchy) + { + deepestHierarchy = currentHierarchyDepth; + methWithDeepestHierarchy = match[i]; + } + } + + return methWithDeepestHierarchy; + } + + // CanConvertPrimitive + // This will determine if the source can be converted to the target type + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern bool CanConvertPrimitive(RuntimeType source,RuntimeType target); + + // CanConvertPrimitiveObjectToType + // This method will determine if the primitive object can be converted + // to a type. + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + static internal extern bool CanConvertPrimitiveObjectToType(Object source,RuntimeType type); + + // This method will sort the vars array into the mapping order stored + // in the paramOrder array. + private static void ReorderParams(int[] paramOrder,Object[] vars) + { + object[] varsCopy = new object[vars.Length]; + for (int i = 0; i < vars.Length; i ++) + varsCopy[i] = vars[i]; + + for (int i = 0; i < vars.Length; i ++) + vars[i] = varsCopy[paramOrder[i]]; + } + + // This method will create the mapping between the Parameters and the underlying + // data based upon the names array. The names array is stored in the same order + // as the values and maps to the parameters of the method. We store the mapping + // from the parameters to the names in the paramOrder array. All parameters that + // don't have matching names are then stored in the array in order. + private static bool CreateParamOrder(int[] paramOrder,ParameterInfo[] pars,String[] names) + { + bool[] used = new bool[pars.Length]; + + // Mark which parameters have not been found in the names list + for (int i=0;i<pars.Length;i++) + paramOrder[i] = -1; + // Find the parameters with names. + for (int i=0;i<names.Length;i++) { + int j; + for (j=0;j<pars.Length;j++) { + if (names[i].Equals(pars[j].Name)) { + paramOrder[j] = i; + used[i] = true; + break; + } + } + // This is an error condition. The name was not found. This + // method must not match what we sent. + if (j == pars.Length) + return false; + } + + // Now we fill in the holes with the parameters that are unused. + int pos = 0; + for (int i=0;i<pars.Length;i++) { + if (paramOrder[i] == -1) { + for (;pos<pars.Length;pos++) { + if (!used[pos]) { + paramOrder[i] = pos; + pos++; + break; + } + } + } + } + return true; + } + + internal class BinderState { + internal int[] m_argsMap; + internal int m_originalSize; + internal bool m_isParamArray; + + internal BinderState(int[] argsMap, int originalSize, bool isParamArray) { + m_argsMap = argsMap; + m_originalSize = originalSize; + m_isParamArray = isParamArray; + } - return LimitedBinder.SelectProperty(memberArray, returnType, indexes); } - private const BindingFlags SupportedBindingFlags = BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs new file mode 100644 index 000000000..c3cc15ca4 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// +// +// Implements System.RuntimeType +// +// ====================================================================================== + + +using System; +using System.Reflection; +using System.Runtime.ConstrainedExecution; +using System.Globalization; +using System.Threading; +using System.Diagnostics; +using System.Security.Permissions; +using System.Collections; +using System.Collections.Generic; +using System.Runtime; +using System.Runtime.Serialization; +using System.Runtime.CompilerServices; +using System.Security; +using System.Text; +using System.Runtime.Remoting; +#if FEATURE_REMOTING +using System.Runtime.Remoting.Proxies; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Activation; +using System.Runtime.Remoting.Metadata; +#endif +using MdSigCallingConvention = System.Signature.MdSigCallingConvention; +using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; +using System.Runtime.InteropServices; +using DebuggerStepThroughAttribute = System.Reflection.DebuggerStepThroughAttribute; +using MdToken = System.Reflection.MetadataToken; +using System.Runtime.Versioning; +using System.Diagnostics.Contracts; + +namespace System +{ + [Serializable] + internal class RuntimeType : + System.Reflection.TypeInfo, ISerializable, ICloneable + { + // Used by GetMethodCandidates/GetConstructorCandidates, InvokeMember, and CreateInstanceImpl to perform the necessary filtering. + // Should only be called by FilterApplyMethodInfo and FilterApplyConstructorInfo. + private static bool FilterApplyMethodBase( + MethodBase methodBase, BindingFlags methodFlags, BindingFlags bindingFlags, CallingConventions callConv, Type[] argumentTypes) + { + Contract.Requires(methodBase != null); + + bindingFlags ^= BindingFlags.DeclaredOnly; + + #region Apply Base Filter + if ((bindingFlags & methodFlags) != methodFlags) + return false; + #endregion + + #region Check CallingConvention + if ((callConv & CallingConventions.Any) == 0) + { + if ((callConv & CallingConventions.VarArgs) != 0 && + (methodBase.CallingConvention & CallingConventions.VarArgs) == 0) + return false; + + if ((callConv & CallingConventions.Standard) != 0 && + (methodBase.CallingConvention & CallingConventions.Standard) == 0) + return false; + } + #endregion + + #region If argumentTypes supplied + if (argumentTypes != null) + { + ParameterInfo[] parameterInfos = methodBase.GetParametersNoCopy(); + + if (argumentTypes.Length != parameterInfos.Length) + { + #region Invoke Member, Get\Set & Create Instance specific case + // If the number of supplied arguments differs than the number in the signature AND + // we are not filtering for a dynamic call -- InvokeMethod or CreateInstance -- filter out the method. + if ((bindingFlags & + (BindingFlags.InvokeMethod | BindingFlags.CreateInstance | BindingFlags.GetProperty | BindingFlags.SetProperty)) == 0) + return false; + + bool testForParamArray = false; + bool excessSuppliedArguments = argumentTypes.Length > parameterInfos.Length; + + if (excessSuppliedArguments) + { // more supplied arguments than parameters, additional arguments could be vararg + #region Varargs + // If method is not vararg, additional arguments can not be passed as vararg + if ((methodBase.CallingConvention & CallingConventions.VarArgs) == 0) + { + testForParamArray = true; + } + else + { + // If Binding flags did not include varargs we would have filtered this vararg method. + // This Invariant established during callConv check. + Contract.Assert((callConv & CallingConventions.VarArgs) != 0); + } + #endregion + } + else + {// fewer supplied arguments than parameters, missing arguments could be optional + #region OptionalParamBinding + if ((bindingFlags & BindingFlags.OptionalParamBinding) == 0) + { + testForParamArray = true; + } + else + { + // From our existing code, our policy here is that if a parameterInfo + // is optional then all subsequent parameterInfos shall be optional. + + // Thus, iff the first parameterInfo is not optional then this MethodInfo is no longer a canidate. + if (!parameterInfos[argumentTypes.Length].IsOptional) + testForParamArray = true; + } + #endregion + } + + #region ParamArray + if (testForParamArray) + { + if (parameterInfos.Length == 0) + return false; + + // The last argument of the signature could be a param array. + bool shortByMoreThanOneSuppliedArgument = argumentTypes.Length < parameterInfos.Length - 1; + + if (shortByMoreThanOneSuppliedArgument) + return false; + + ParameterInfo lastParameter = parameterInfos[parameterInfos.Length - 1]; + + if (!lastParameter.ParameterType.IsArray) + return false; + + if (!lastParameter.IsDefined(typeof(ParamArrayAttribute), false)) + return false; + } + #endregion + + #endregion + } + else + { + #region Exact Binding + if ((bindingFlags & BindingFlags.ExactBinding) != 0) + { + // Legacy behavior is to ignore ExactBinding when InvokeMember is specified. + // Why filter by InvokeMember? If the answer is we leave this to the binder then why not leave + // all the rest of this to the binder too? Further, what other semanitc would the binder + // use for BindingFlags.ExactBinding besides this one? Further, why not include CreateInstance + // in this if statement? That's just InvokeMethod with a constructor, right? + if ((bindingFlags & (BindingFlags.InvokeMethod)) == 0) + { + for(int i = 0; i < parameterInfos.Length; i ++) + { + // a null argument type implies a null arg which is always a perfect match + if ((object)argumentTypes[i] != null && !Object.ReferenceEquals(parameterInfos[i].ParameterType, argumentTypes[i])) + return false; + } + } + } + #endregion + } + } + #endregion + + return true; + } + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ListBuilder.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ListBuilder.cs new file mode 100644 index 000000000..0c3a1f50e --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/ListBuilder.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// +// +// Implements System.RuntimeType +// +// ====================================================================================== + + +using System; +using System.Reflection; +using System.Runtime.ConstrainedExecution; +using System.Globalization; +using System.Threading; +using System.Diagnostics; +using System.Security.Permissions; +using System.Collections; +using System.Collections.Generic; +using System.Runtime; +using System.Runtime.Serialization; +using System.Runtime.CompilerServices; +using System.Security; +using System.Text; +using System.Runtime.Remoting; +#if FEATURE_REMOTING +using System.Runtime.Remoting.Proxies; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Activation; +using System.Runtime.Remoting.Metadata; +#endif +using MdSigCallingConvention = System.Signature.MdSigCallingConvention; +using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache; +using System.Runtime.InteropServices; +using DebuggerStepThroughAttribute = System.Reflection.DebuggerStepThroughAttribute; +using MdToken = System.Reflection.MetadataToken; +using System.Runtime.Versioning; +using System.Diagnostics.Contracts; + +namespace System +{ + [Serializable] + internal class RuntimeType : + System.Reflection.TypeInfo, ISerializable, ICloneable + { + // Helper to build lists of MemberInfos. Special cased to avoid allocations for lists of one element. + private struct ListBuilder<T> where T : class + { + T[] _items; + T _item; + int _count; + int _capacity; + + public ListBuilder(int capacity) + { + _items = null; + _item = null; + _count = 0; + _capacity = capacity; + } + + public T this[int index] + { + get + { + Contract.Requires(index < Count); + return (_items != null) ? _items[index] : _item; + } + } + + public T[] ToArray() + { + if (_count == 0) + return EmptyArray<T>.Value; + if (_count == 1) + return new T[1] { _item }; + + Array.Resize(ref _items, _count); + _capacity = _count; + return _items; + } + + public void CopyTo(Object[] array, int index) + { + if (_count == 0) + return; + + if (_count == 1) + { + array[index] = _item; + return; + } + + Array.Copy(_items, 0, array, index, _count); + } + + public int Count + { + get + { + return _count; + } + } + + public void Add(T item) + { + if (_count == 0) + { + _item = item; + } + else + { + if (_count == 1) + { + if (_capacity < 2) + _capacity = 4; + _items = new T[_capacity]; + _items[0] = _item; + } + else + if (_capacity == _count) + { + int newCapacity = 2 * _capacity; + Array.Resize(ref _items, newCapacity); + _capacity = newCapacity; + } + + _items[_count] = item; + } + _count++; + } + } + } +} |