|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
//
// File: RtType.cs
//
// <OWNER>Microsoft</OWNER>
//
// 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.Diagnostics.DebuggerStepThroughAttribute;
using MdToken = System.Reflection.MetadataToken;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
namespace System
{
// this is a work around to get the concept of a calli. It's not as fast but it would be interesting to
// see how it compares to the current implementation.
// This delegate will disappear at some point in favor of calli
internal delegate void CtorDelegate(Object instance);
// Keep this in sync with FormatFlags defined in typestring.h
internal enum TypeNameFormatFlags
{
FormatBasic = 0x00000000, // Not a bitmask, simply the tersest flag settings possible
FormatNamespace = 0x00000001, // Include namespace and/or enclosing class names in type names
FormatFullInst = 0x00000002, // Include namespace and assembly in generic types (regardless of other flag settings)
FormatAssembly = 0x00000004, // Include assembly display name in type names
FormatSignature = 0x00000008, // Include signature in method names
FormatNoVersion = 0x00000010, // Suppress version and culture information in all assembly names
#if _DEBUG
FormatDebug = 0x00000020, // For debug printing of types only
#endif
FormatAngleBrackets = 0x00000040, // Whether generic types are C<T> or C[T]
FormatStubInfo = 0x00000080, // Include stub info like {unbox-stub}
FormatGenericParam = 0x00000100, // Use !name and !!name for generic type and method parameters
// If we want to be able to distinguish between overloads whose parameter types have the same name but come from different assemblies,
// we can add FormatAssembly | FormatNoVersion to FormatSerialization. But we are omitting it because it is not a useful scenario
// and including the assembly name will normally increase the size of the serialized data and also decrease the performance.
FormatSerialization = FormatNamespace |
FormatGenericParam |
FormatFullInst
}
internal enum TypeNameKind
{
Name,
ToString,
SerializationName,
FullName,
}
[Serializable]
internal class RuntimeType :
System.Reflection.TypeInfo, ISerializable, ICloneable
{
#region Definitions
internal enum MemberListType
{
All,
CaseSensitive,
CaseInsensitive,
HandleToInfo
}
// 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;
}
#if FEATURE_LEGACYNETCF
// added for Dev11 466969 quirk
set
{
Contract.Requires(index < Count);
if (_items != null)
_items[index] = value;
else
_item = value;
}
#endif
}
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++;
}
}
internal class RuntimeTypeCache
{
private const int MAXNAMELEN = 1024;
#region Definitions
internal enum CacheType
{
Method,
Constructor,
Field,
Property,
Event,
Interface,
NestedType
}
private struct Filter
{
private Utf8String m_name;
private MemberListType m_listType;
private uint m_nameHash;
[System.Security.SecurityCritical] // auto-generated
public unsafe Filter(byte* pUtf8Name, int cUtf8Name, MemberListType listType)
{
this.m_name = new Utf8String((void*) pUtf8Name, cUtf8Name);
this.m_listType = listType;
this.m_nameHash = 0;
if (RequiresStringComparison())
{
m_nameHash = m_name.HashCaseInsensitive();
}
}
public bool Match(Utf8String name)
{
bool retVal = true;
if (m_listType == MemberListType.CaseSensitive)
retVal = m_name.Equals(name);
else if (m_listType == MemberListType.CaseInsensitive)
retVal = m_name.EqualsCaseInsensitive(name);
// Currently the callers of UsesStringComparison assume that if it returns false
// then the match always succeeds and can be skipped. Assert that this is maintained.
Contract.Assert(retVal || RequiresStringComparison());
return retVal;
}
// Does the current match type require a string comparison?
// If not, we know Match will always return true and the call can be skipped
// If so, we know we can have a valid hash to check against from GetHashToMatch
public bool RequiresStringComparison()
{
return (m_listType == MemberListType.CaseSensitive) ||
(m_listType == MemberListType.CaseInsensitive);
}
public bool CaseSensitive()
{
return (m_listType == MemberListType.CaseSensitive);
}
public uint GetHashToMatch()
{
Contract.Assert(RequiresStringComparison());
return m_nameHash;
}
}
private class MemberInfoCache<T> where T : MemberInfo
{
#region Private Data Members
// MemberInfo caches
private CerHashtable<string, T[]> m_csMemberInfos;
private CerHashtable<string, T[]> m_cisMemberInfos;
// List of MemberInfos given out. When m_cacheComplete is false, it may have null entries at the end to avoid
// reallocating the list every time a new entry is added.
private T[] m_allMembers;
private bool m_cacheComplete;
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
private List<RuntimePropertyInfo> m_ambiguousProperties;
#endif
// This is the strong reference back to the cache
private RuntimeTypeCache m_runtimeTypeCache;
#endregion
#region Constructor
#if MDA_SUPPORTED
[System.Security.SecuritySafeCritical] // auto-generated
#endif
internal MemberInfoCache(RuntimeTypeCache runtimeTypeCache)
{
#if MDA_SUPPORTED
Mda.MemberInfoCacheCreation();
#endif
m_runtimeTypeCache = runtimeTypeCache;
}
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
internal IReadOnlyList<RuntimePropertyInfo> AmbiguousProperties { get { return m_ambiguousProperties; } }
private void InitializeAndUpdateAmbiguousPropertiesList(RuntimePropertyInfo parent, RuntimePropertyInfo child)
{
Contract.Assert(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8);
if (m_ambiguousProperties == null)
{
List<RuntimePropertyInfo> newList = new List<RuntimePropertyInfo>();
Interlocked.CompareExchange(ref m_ambiguousProperties, newList, null);
}
lock (m_ambiguousProperties)
{
// record the parent type in case it needs to be pruned later.
Contract.Assert(child.DeclaringType.IsSubclassOf(parent.DeclaringType));
m_ambiguousProperties.Add(parent);
}
}
#endif
[System.Security.SecuritySafeCritical] // auto-generated
internal MethodBase AddMethod(RuntimeType declaringType, RuntimeMethodHandleInternal method, CacheType cacheType)
{
T[] list = null;
MethodAttributes methodAttributes = RuntimeMethodHandle.GetAttributes(method);
bool isPublic = (methodAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
bool isStatic = (methodAttributes & MethodAttributes.Static) != 0;
bool isInherited = declaringType != ReflectedType;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
switch (cacheType)
{
case CacheType.Method:
list = (T[])(object)new RuntimeMethodInfo[1] {
new RuntimeMethodInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags, null)
};
break;
case CacheType.Constructor:
list = (T[])(object)new RuntimeConstructorInfo[1] {
new RuntimeConstructorInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags)
};
break;
}
Insert(ref list, null, MemberListType.HandleToInfo);
return (MethodBase)(object)list[0];
}
[System.Security.SecuritySafeCritical] // auto-generated
internal FieldInfo AddField(RuntimeFieldHandleInternal field)
{
// create the runtime field info
FieldAttributes fieldAttributes = RuntimeFieldHandle.GetAttributes(field);
bool isPublic = (fieldAttributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public;
bool isStatic = (fieldAttributes & FieldAttributes.Static) != 0;
RuntimeType approxDeclaringType = RuntimeFieldHandle.GetApproxDeclaringType(field);
bool isInherited = RuntimeFieldHandle.AcquiresContextFromThis(field) ?
!RuntimeTypeHandle.CompareCanonicalHandles(approxDeclaringType, ReflectedType) :
approxDeclaringType != ReflectedType;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
T[] list = (T[])(object)new RuntimeFieldInfo[1] {
new RtFieldInfo(field, ReflectedType, m_runtimeTypeCache, bindingFlags)
};
Insert(ref list, null, MemberListType.HandleToInfo);
return (FieldInfo)(object)list[0];
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe T[] Populate(string name, MemberListType listType, CacheType cacheType)
{
T[] list = null;
if (name == null || name.Length == 0 ||
(cacheType == CacheType.Constructor && name.FirstChar != '.' && name.FirstChar != '*'))
{
list = GetListByName(null, 0, null, 0, listType, cacheType);
}
else
{
int cNameLen = name.Length;
fixed (char* pName = name)
{
int cUtf8Name = Encoding.UTF8.GetByteCount(pName, cNameLen);
// allocating on the stack is faster than allocating on the GC heap
// but we surely don't want to cause a stack overflow
// no one should be looking for a member whose name is longer than 1024
if (cUtf8Name > MAXNAMELEN)
{
fixed (byte* pUtf8Name = new byte[cUtf8Name])
{
list = GetListByName(pName, cNameLen, pUtf8Name, cUtf8Name, listType, cacheType);
}
}
else
{
byte* pUtf8Name = stackalloc byte[cUtf8Name];
list = GetListByName(pName, cNameLen, pUtf8Name, cUtf8Name, listType, cacheType);
}
}
}
Insert(ref list, name, listType);
return list;
}
[System.Security.SecurityCritical] // auto-generated
private unsafe T[] GetListByName(char* pName, int cNameLen, byte* pUtf8Name, int cUtf8Name, MemberListType listType, CacheType cacheType)
{
if (cNameLen != 0)
Encoding.UTF8.GetBytes(pName, cNameLen, pUtf8Name, cUtf8Name);
Filter filter = new Filter(pUtf8Name, cUtf8Name, listType);
Object list = null;
switch (cacheType)
{
case CacheType.Method:
list = PopulateMethods(filter);
break;
case CacheType.Field:
list = PopulateFields(filter);
break;
case CacheType.Constructor:
list = PopulateConstructors(filter);
break;
case CacheType.Property:
list = PopulateProperties(filter);
break;
case CacheType.Event:
list = PopulateEvents(filter);
break;
case CacheType.NestedType:
list = PopulateNestedClasses(filter);
break;
case CacheType.Interface:
list = PopulateInterfaces(filter);
break;
default:
BCLDebug.Assert(true, "Invalid CacheType");
break;
}
return (T[])list;
}
// May replace the list with a new one if certain cache
// lookups succeed. Also, may modify the contents of the list
// after merging these new data structures with cached ones.
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal void Insert(ref T[] list, string name, MemberListType listType)
{
bool lockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref lockTaken);
switch (listType)
{
case MemberListType.CaseSensitive:
{
// Ensure we always return a list that has
// been merged with the global list.
T[] cachedList = m_csMemberInfos[name];
if (cachedList == null)
{
MergeWithGlobalList(list);
m_csMemberInfos[name] = list;
}
else
list = cachedList;
}
break;
case MemberListType.CaseInsensitive:
{
// Ensure we always return a list that has
// been merged with the global list.
T[] cachedList = m_cisMemberInfos[name];
if (cachedList == null)
{
MergeWithGlobalList(list);
m_cisMemberInfos[name] = list;
}
else
list = cachedList;
}
break;
case MemberListType.All:
if (!m_cacheComplete)
{
MergeWithGlobalList(list);
// Trim null entries at the end of m_allMembers array
int memberCount = m_allMembers.Length;
while (memberCount > 0)
{
if (m_allMembers[memberCount-1] != null)
break;
memberCount--;
}
Array.Resize(ref m_allMembers, memberCount);
Volatile.Write(ref m_cacheComplete, true);
}
// We want the behavior where the results are returned in the same order on the phone
#if !FEATURE_LEGACYNETCF
else
#endif
list = m_allMembers;
break;
default:
MergeWithGlobalList(list);
break;
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(this);
}
}
}
// Modifies the existing list.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private void MergeWithGlobalList(T[] list)
{
T[] cachedMembers = m_allMembers;
if (cachedMembers == null)
{
m_allMembers = list;
return;
}
int cachedCount = cachedMembers.Length;
int freeSlotIndex = 0;
for (int i = 0; i < list.Length; i++)
{
T newMemberInfo = list[i];
bool foundInCache = false;
int cachedIndex;
for (cachedIndex = 0; cachedIndex < cachedCount; cachedIndex++)
{
T cachedMemberInfo = cachedMembers[cachedIndex];
if (cachedMemberInfo == null)
break;
if (newMemberInfo.CacheEquals(cachedMemberInfo))
{
list[i] = cachedMemberInfo;
foundInCache = true;
break;
}
}
if (!foundInCache)
{
if (freeSlotIndex == 0)
freeSlotIndex = cachedIndex;
if (freeSlotIndex >= cachedMembers.Length)
{
int newSize;
if (m_cacheComplete)
{
//
// In theory, we should never add more elements to the cache when it is complete.
//
// Unfortunately, we shipped with bugs that cause changes of the complete cache (DevDiv #339308).
// Grow the list by exactly one element in this case to avoid null entries at the end.
//
// DevDiv #339308 is fixed, but we are keeping this code here for Dev11 in case there are other instances of this bug.
// Remove for Dev12.
Contract.Assert(false);
newSize = cachedMembers.Length + 1;
}
else
{
newSize = Math.Max(Math.Max(4, 2 * cachedMembers.Length), list.Length);
}
// Use different variable for ref argument to Array.Resize to allow enregistration of cachedMembers by the JIT
T[] cachedMembers2 = cachedMembers;
Array.Resize(ref cachedMembers2, newSize);
cachedMembers = cachedMembers2;
}
Contract.Assert(cachedMembers[freeSlotIndex] == null);
cachedMembers[freeSlotIndex] = newMemberInfo;
freeSlotIndex++;
}
}
m_allMembers = cachedMembers;
}
#endregion
#region Population Logic
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe RuntimeMethodInfo[] PopulateMethods(Filter filter)
{
ListBuilder<RuntimeMethodInfo> list = new ListBuilder<RuntimeMethodInfo>();
RuntimeType declaringType = ReflectedType;
Contract.Assert(declaringType != null);
if (RuntimeTypeHandle.IsInterface(declaringType))
{
#region IsInterface
foreach (RuntimeMethodHandleInternal methodHandle in RuntimeTypeHandle.GetIntroducedMethods(declaringType))
{
if (filter.RequiresStringComparison())
{
if (!RuntimeMethodHandle.MatchesNameHash(methodHandle, filter.GetHashToMatch()))
{
Contract.Assert(!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)));
continue;
}
if (!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)))
continue;
}
#region Loop through all methods on the interface
Contract.Assert(!methodHandle.IsNullHandle());
// Except for .ctor, .cctor, IL_STUB*, and static methods, all interface methods should be abstract, virtual, and non-RTSpecialName.
// Note that this assumption will become invalid when we add support for non-abstract or static methods on interfaces.
Contract.Assert(
(RuntimeMethodHandle.GetAttributes(methodHandle) & (MethodAttributes.RTSpecialName | MethodAttributes.Abstract | MethodAttributes.Virtual)) == (MethodAttributes.Abstract | MethodAttributes.Virtual) ||
(RuntimeMethodHandle.GetAttributes(methodHandle) & MethodAttributes.Static) == MethodAttributes.Static ||
RuntimeMethodHandle.GetName(methodHandle).Equals(".ctor") ||
RuntimeMethodHandle.GetName(methodHandle).Equals(".cctor") ||
RuntimeMethodHandle.GetName(methodHandle).StartsWith("IL_STUB", StringComparison.Ordinal));
#region Calculate Binding Flags
MethodAttributes methodAttributes = RuntimeMethodHandle.GetAttributes(methodHandle);
bool isPublic = (methodAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
bool isStatic = (methodAttributes & MethodAttributes.Static) != 0;
bool isInherited = false;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
#endregion
if ((methodAttributes & MethodAttributes.RTSpecialName) != 0)
continue;
// get the unboxing stub or instantiating stub if needed
RuntimeMethodHandleInternal instantiatedHandle = RuntimeMethodHandle.GetStubIfNeeded(methodHandle, declaringType, null);
RuntimeMethodInfo runtimeMethodInfo = new RuntimeMethodInfo(
instantiatedHandle, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags, null);
list.Add(runtimeMethodInfo);
#endregion
}
#endregion
}
else
{
#region IsClass or GenericParameter
while(RuntimeTypeHandle.IsGenericVariable(declaringType))
declaringType = declaringType.GetBaseType();
bool* overrides = stackalloc bool[RuntimeTypeHandle.GetNumVirtuals(declaringType)];
bool isValueType = declaringType.IsValueType;
do
{
int vtableSlots = RuntimeTypeHandle.GetNumVirtuals(declaringType);
foreach (RuntimeMethodHandleInternal methodHandle in RuntimeTypeHandle.GetIntroducedMethods(declaringType))
{
if (filter.RequiresStringComparison())
{
if (!RuntimeMethodHandle.MatchesNameHash(methodHandle, filter.GetHashToMatch()))
{
Contract.Assert(!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)));
continue;
}
if (!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)))
continue;
}
#region Loop through all methods on the current type
Contract.Assert(!methodHandle.IsNullHandle());
MethodAttributes methodAttributes = RuntimeMethodHandle.GetAttributes(methodHandle);
MethodAttributes methodAccess = methodAttributes & MethodAttributes.MemberAccessMask;
#region Continue if this is a constructor
Contract.Assert(
(RuntimeMethodHandle.GetAttributes(methodHandle) & MethodAttributes.RTSpecialName) == 0 ||
RuntimeMethodHandle.GetName(methodHandle).Equals(".ctor") ||
RuntimeMethodHandle.GetName(methodHandle).Equals(".cctor"));
if ((methodAttributes & MethodAttributes.RTSpecialName) != 0)
continue;
#endregion
#region Continue if this is a private declared on a base type
bool isVirtual = false;
int methodSlot = 0;
if ((methodAttributes & MethodAttributes.Virtual) != 0)
{
// only virtual if actually in the vtableslot range, but GetSlot will
// assert if an EnC method, which can't be virtual, so narrow down first
// before calling GetSlot
methodSlot = RuntimeMethodHandle.GetSlot(methodHandle);
isVirtual = (methodSlot < vtableSlots);
}
bool isInherited = declaringType != ReflectedType;
// NetCF actually includes private methods from parent classes in Reflection results
// We will mimic that in Mango Compat mode.
if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
bool isPrivate = methodAccess == MethodAttributes.Private;
if (isInherited && isPrivate && !isVirtual)
continue;
}
#endregion
#region Continue if this is a virtual and is already overridden
if (isVirtual)
{
Contract.Assert(
(methodAttributes & MethodAttributes.Abstract) != 0 ||
(methodAttributes & MethodAttributes.Virtual) != 0 ||
RuntimeMethodHandle.GetDeclaringType(methodHandle) != declaringType);
if (overrides[methodSlot] == true)
continue;
overrides[methodSlot] = true;
}
else if (isValueType)
{
if ((methodAttributes & (MethodAttributes.Virtual | MethodAttributes.Abstract)) != 0)
continue;
}
else
{
Contract.Assert((methodAttributes & (MethodAttributes.Virtual | MethodAttributes.Abstract)) == 0);
}
#endregion
#region Calculate Binding Flags
bool isPublic = methodAccess == MethodAttributes.Public;
bool isStatic = (methodAttributes & MethodAttributes.Static) != 0;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
#endregion
// get the unboxing stub or instantiating stub if needed
RuntimeMethodHandleInternal instantiatedHandle = RuntimeMethodHandle.GetStubIfNeeded(methodHandle, declaringType, null);
RuntimeMethodInfo runtimeMethodInfo = new RuntimeMethodInfo(
instantiatedHandle, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags, null);
list.Add(runtimeMethodInfo);
#endregion
}
declaringType = RuntimeTypeHandle.GetBaseType(declaringType);
} while (declaringType != null);
#endregion
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private RuntimeConstructorInfo[] PopulateConstructors(Filter filter)
{
if (ReflectedType.IsGenericParameter)
{
return EmptyArray<RuntimeConstructorInfo>.Value;
}
ListBuilder<RuntimeConstructorInfo> list = new ListBuilder<RuntimeConstructorInfo>();
RuntimeType declaringType= ReflectedType;
foreach (RuntimeMethodHandleInternal methodHandle in RuntimeTypeHandle.GetIntroducedMethods(declaringType))
{
if (filter.RequiresStringComparison())
{
if (!RuntimeMethodHandle.MatchesNameHash(methodHandle, filter.GetHashToMatch()))
{
Contract.Assert(!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)));
continue;
}
if (!filter.Match(RuntimeMethodHandle.GetUtf8Name(methodHandle)))
continue;
}
MethodAttributes methodAttributes = RuntimeMethodHandle.GetAttributes(methodHandle);
Contract.Assert(!methodHandle.IsNullHandle());
if ((methodAttributes & MethodAttributes.RTSpecialName) == 0)
continue;
// Constructors should not be virtual or abstract
Contract.Assert(
(methodAttributes & MethodAttributes.Abstract) == 0 &&
(methodAttributes & MethodAttributes.Virtual) == 0);
#region Calculate Binding Flags
bool isPublic = (methodAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
bool isStatic = (methodAttributes & MethodAttributes.Static) != 0;
bool isInherited = false;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
#endregion
// get the unboxing stub or instantiating stub if needed
RuntimeMethodHandleInternal instantiatedHandle = RuntimeMethodHandle.GetStubIfNeeded(methodHandle, declaringType, null);
RuntimeConstructorInfo runtimeConstructorInfo =
new RuntimeConstructorInfo(instantiatedHandle, ReflectedType, m_runtimeTypeCache, methodAttributes, bindingFlags);
list.Add(runtimeConstructorInfo);
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe RuntimeFieldInfo[] PopulateFields(Filter filter)
{
ListBuilder<RuntimeFieldInfo> list = new ListBuilder<RuntimeFieldInfo>();
RuntimeType declaringType = ReflectedType;
#region Populate all static, instance and literal fields
while(RuntimeTypeHandle.IsGenericVariable(declaringType))
declaringType = declaringType.GetBaseType();
while(declaringType != null)
{
PopulateRtFields(filter, declaringType, ref list);
PopulateLiteralFields(filter, declaringType, ref list);
declaringType = RuntimeTypeHandle.GetBaseType(declaringType);
}
#endregion
#region Populate Literal Fields on Interfaces
if (ReflectedType.IsGenericParameter)
{
Type[] interfaces = ReflectedType.BaseType.GetInterfaces();
for (int i = 0; i < interfaces.Length; i++)
{
// Populate literal fields defined on any of the interfaces implemented by the declaring type
PopulateLiteralFields(filter, (RuntimeType)interfaces[i], ref list);
PopulateRtFields(filter, (RuntimeType)interfaces[i], ref list);
}
}
else
{
Type[] interfaces = RuntimeTypeHandle.GetInterfaces(ReflectedType);
if (interfaces != null)
{
for (int i = 0; i < interfaces.Length; i++)
{
// Populate literal fields defined on any of the interfaces implemented by the declaring type
PopulateLiteralFields(filter, (RuntimeType)interfaces[i], ref list);
PopulateRtFields(filter, (RuntimeType)interfaces[i], ref list);
}
}
}
#endregion
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe void PopulateRtFields(Filter filter, RuntimeType declaringType, ref ListBuilder<RuntimeFieldInfo> list)
{
IntPtr* pResult = stackalloc IntPtr[64];
int count = 64;
if (!RuntimeTypeHandle.GetFields(declaringType, pResult, &count))
{
fixed(IntPtr* pBigResult = new IntPtr[count])
{
RuntimeTypeHandle.GetFields(declaringType, pBigResult, &count);
PopulateRtFields(filter, pBigResult, count, declaringType, ref list);
}
}
else if (count > 0)
{
PopulateRtFields(filter, pResult, count, declaringType, ref list);
}
}
[System.Security.SecurityCritical] // auto-generated
private unsafe void PopulateRtFields(Filter filter,
IntPtr* ppFieldHandles, int count, RuntimeType declaringType, ref ListBuilder<RuntimeFieldInfo> list)
{
Contract.Requires(declaringType != null);
Contract.Requires(ReflectedType != null);
bool needsStaticFieldForGeneric = RuntimeTypeHandle.HasInstantiation(declaringType) && !RuntimeTypeHandle.ContainsGenericVariables(declaringType);
bool isInherited = declaringType != ReflectedType;
for(int i = 0; i < count; i ++)
{
RuntimeFieldHandleInternal runtimeFieldHandle = new RuntimeFieldHandleInternal(ppFieldHandles[i]);
if (filter.RequiresStringComparison())
{
if (!RuntimeFieldHandle.MatchesNameHash(runtimeFieldHandle, filter.GetHashToMatch()))
{
Contract.Assert(!filter.Match(RuntimeFieldHandle.GetUtf8Name(runtimeFieldHandle)));
continue;
}
if (!filter.Match(RuntimeFieldHandle.GetUtf8Name(runtimeFieldHandle)))
continue;
}
Contract.Assert(!runtimeFieldHandle.IsNullHandle());
FieldAttributes fieldAttributes = RuntimeFieldHandle.GetAttributes(runtimeFieldHandle);
FieldAttributes fieldAccess = fieldAttributes & FieldAttributes.FieldAccessMask;
if (isInherited)
{
if (fieldAccess == FieldAttributes.Private)
continue;
}
#region Calculate Binding Flags
bool isPublic = fieldAccess == FieldAttributes.Public;
bool isStatic = (fieldAttributes & FieldAttributes.Static) != 0;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
#endregion
// correct the FieldDesc if needed
if (needsStaticFieldForGeneric && isStatic)
runtimeFieldHandle = RuntimeFieldHandle.GetStaticFieldForGenericType(runtimeFieldHandle, declaringType);
RuntimeFieldInfo runtimeFieldInfo =
new RtFieldInfo(runtimeFieldHandle, declaringType, m_runtimeTypeCache, bindingFlags);
list.Add(runtimeFieldInfo);
}
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe void PopulateLiteralFields(Filter filter, RuntimeType declaringType, ref ListBuilder<RuntimeFieldInfo> list)
{
Contract.Requires(declaringType != null);
Contract.Requires(ReflectedType != null);
int tkDeclaringType = RuntimeTypeHandle.GetToken(declaringType);
// Our policy is that TypeDescs do not have metadata tokens
if (MdToken.IsNullToken(tkDeclaringType))
return;
MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
MetadataEnumResult tkFields;
scope.EnumFields(tkDeclaringType, out tkFields);
for (int i = 0; i < tkFields.Length; i++)
{
int tkField = tkFields[i];
Contract.Assert(MdToken.IsTokenOfType(tkField, MetadataTokenType.FieldDef));
Contract.Assert(!MdToken.IsNullToken(tkField));
FieldAttributes fieldAttributes;
scope.GetFieldDefProps(tkField, out fieldAttributes);
FieldAttributes fieldAccess = fieldAttributes & FieldAttributes.FieldAccessMask;
if ((fieldAttributes & FieldAttributes.Literal) != 0)
{
bool isInherited = declaringType != ReflectedType;
if (isInherited)
{
bool isPrivate = fieldAccess == FieldAttributes.Private;
if (isPrivate)
continue;
}
if (filter.RequiresStringComparison())
{
Utf8String name;
name = scope.GetName(tkField);
if (!filter.Match(name))
continue;
}
#region Calculate Binding Flags
bool isPublic = fieldAccess == FieldAttributes.Public;
bool isStatic = (fieldAttributes & FieldAttributes.Static) != 0;
BindingFlags bindingFlags = RuntimeType.FilterPreCalculate(isPublic, isInherited, isStatic);
#endregion
RuntimeFieldInfo runtimeFieldInfo =
new MdFieldInfo(tkField, fieldAttributes, declaringType.GetTypeHandleInternal(), m_runtimeTypeCache, bindingFlags);
list.Add(runtimeFieldInfo);
}
}
}
private static void AddElementTypes(Type template, IList<Type> types)
{
if (!template.HasElementType)
return;
AddElementTypes(template.GetElementType(), types);
for (int i = 0; i < types.Count; i ++)
{
if (template.IsArray)
{
if (template.IsSzArray)
types[i] = types[i].MakeArrayType();
else
types[i] = types[i].MakeArrayType(template.GetArrayRank());
}
else if (template.IsPointer)
{
types[i] = types[i].MakePointerType();
}
}
}
private void AddSpecialInterface(ref ListBuilder<RuntimeType> list, Filter filter, RuntimeType iList, bool addSubInterface)
{
if (iList.IsAssignableFrom(ReflectedType))
{
if (filter.Match(RuntimeTypeHandle.GetUtf8Name(iList)))
list.Add(iList);
if (addSubInterface)
{
Type[] iFaces = iList.GetInterfaces();
for (int j = 0; j < iFaces.Length; j++)
{
RuntimeType iFace = (RuntimeType)iFaces[j];
if (iFace.IsGenericType && filter.Match(RuntimeTypeHandle.GetUtf8Name(iFace)))
list.Add(iFace);
}
}
}
}
[System.Security.SecuritySafeCritical] // auto-generated
private RuntimeType[] PopulateInterfaces(Filter filter)
{
ListBuilder<RuntimeType> list = new ListBuilder<RuntimeType>();
RuntimeType declaringType = ReflectedType;
if (!RuntimeTypeHandle.IsGenericVariable(declaringType))
{
Type[] ifaces = RuntimeTypeHandle.GetInterfaces(declaringType);
if (ifaces != null)
{
for (int i = 0; i < ifaces.Length; i++)
{
RuntimeType interfaceType = (RuntimeType)ifaces[i];
if (filter.RequiresStringComparison())
{
if (!filter.Match(RuntimeTypeHandle.GetUtf8Name(interfaceType)))
continue;
}
Contract.Assert(interfaceType.IsInterface);
list.Add(interfaceType);
}
}
if (ReflectedType.IsSzArray)
{
RuntimeType arrayType = (RuntimeType)ReflectedType.GetElementType();
if (!arrayType.IsPointer)
{
AddSpecialInterface(ref list, filter, (RuntimeType)typeof(IList<>).MakeGenericType(arrayType), true);
// To avoid adding a duplicate IEnumerable<T>, we don't add the sub interfaces of IReadOnlyList.
// Instead, we add IReadOnlyCollection<T> separately.
AddSpecialInterface(ref list, filter, (RuntimeType)typeof(IReadOnlyList<>).MakeGenericType(arrayType), false);
AddSpecialInterface(ref list, filter, (RuntimeType)typeof(IReadOnlyCollection<>).MakeGenericType(arrayType), false);
}
}
}
else
{
List<RuntimeType> al = new List<RuntimeType>();
// Get all constraints
Type[] constraints = declaringType.GetGenericParameterConstraints();
// Populate transitive closure of all interfaces in constraint set
for (int i = 0; i < constraints.Length; i++)
{
RuntimeType constraint = (RuntimeType)constraints[i];
if (constraint.IsInterface)
al.Add(constraint);
Type[] temp = constraint.GetInterfaces();
for (int j = 0; j < temp.Length; j++)
al.Add(temp[j] as RuntimeType);
}
// Remove duplicates
Dictionary<RuntimeType, RuntimeType> ht = new Dictionary<RuntimeType, RuntimeType>();
for (int i = 0; i < al.Count; i++)
{
RuntimeType constraint = al[i];
if (!ht.ContainsKey(constraint))
ht[constraint] = constraint;
}
RuntimeType[] interfaces = new RuntimeType[ht.Values.Count];
ht.Values.CopyTo(interfaces, 0);
// Populate link-list
for (int i = 0; i < interfaces.Length; i++)
{
if (filter.RequiresStringComparison())
{
if (!filter.Match(RuntimeTypeHandle.GetUtf8Name(interfaces[i])))
continue;
}
list.Add(interfaces[i]);
}
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe RuntimeType[] PopulateNestedClasses(Filter filter)
{
RuntimeType declaringType = ReflectedType;
while (RuntimeTypeHandle.IsGenericVariable(declaringType))
{
declaringType = declaringType.GetBaseType();
}
int tkEnclosingType = RuntimeTypeHandle.GetToken(declaringType);
// For example, TypeDescs do not have metadata tokens
if (MdToken.IsNullToken(tkEnclosingType))
return EmptyArray<RuntimeType>.Value;
ListBuilder<RuntimeType> list = new ListBuilder<RuntimeType>();
RuntimeModule moduleHandle = RuntimeTypeHandle.GetModule(declaringType);
MetadataImport scope = ModuleHandle.GetMetadataImport(moduleHandle);
MetadataEnumResult tkNestedClasses;
scope.EnumNestedTypes(tkEnclosingType, out tkNestedClasses);
for (int i = 0; i < tkNestedClasses.Length; i++)
{
RuntimeType nestedType = null;
try
{
nestedType = ModuleHandle.ResolveTypeHandleInternal(moduleHandle, tkNestedClasses[i], null, null);
}
catch(System.TypeLoadException)
{
// In a reflection emit scenario, we may have a token for a class which
// has not been baked and hence cannot be loaded.
continue;
}
if (filter.RequiresStringComparison())
{
if (!filter.Match(RuntimeTypeHandle.GetUtf8Name(nestedType)))
continue;
}
list.Add(nestedType);
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe RuntimeEventInfo[] PopulateEvents(Filter filter)
{
Contract.Requires(ReflectedType != null);
// Do not create the dictionary if we are filtering the properties by name already
Dictionary<String, RuntimeEventInfo> csEventInfos = filter.CaseSensitive() ? null :
new Dictionary<String, RuntimeEventInfo>();
RuntimeType declaringType = ReflectedType;
ListBuilder<RuntimeEventInfo> list = new ListBuilder<RuntimeEventInfo>();
if (!RuntimeTypeHandle.IsInterface(declaringType))
{
while(RuntimeTypeHandle.IsGenericVariable(declaringType))
declaringType = declaringType.GetBaseType();
// Populate associates off of the class hierarchy
while(declaringType != null)
{
PopulateEvents(filter, declaringType, csEventInfos, ref list);
declaringType = RuntimeTypeHandle.GetBaseType(declaringType);
}
}
else
{
// Populate associates for this interface
PopulateEvents(filter, declaringType, csEventInfos, ref list);
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe void PopulateEvents(
Filter filter, RuntimeType declaringType, Dictionary<String, RuntimeEventInfo> csEventInfos, ref ListBuilder<RuntimeEventInfo> list)
{
int tkDeclaringType = RuntimeTypeHandle.GetToken(declaringType);
// Arrays, Pointers, ByRef types and others generated only the fly by the RT do not have tokens.
if (MdToken.IsNullToken(tkDeclaringType))
return;
MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
MetadataEnumResult tkEvents;
scope.EnumEvents(tkDeclaringType, out tkEvents);
for (int i = 0; i < tkEvents.Length; i++)
{
int tkEvent = tkEvents[i];
bool isPrivate;
Contract.Assert(!MdToken.IsNullToken(tkEvent));
Contract.Assert(MdToken.IsTokenOfType(tkEvent, MetadataTokenType.Event));
if (filter.RequiresStringComparison())
{
Utf8String name;
name = scope.GetName(tkEvent);
if (!filter.Match(name))
continue;
}
RuntimeEventInfo eventInfo = new RuntimeEventInfo(
tkEvent, declaringType, m_runtimeTypeCache, out isPrivate);
#region Remove Inherited Privates
if (declaringType != m_runtimeTypeCache.GetRuntimeType() && isPrivate)
continue;
#endregion
#region Remove Duplicates
if (csEventInfos != null)
{
string name = eventInfo.Name;
if (csEventInfos.GetValueOrDefault(name) != null)
continue;
csEventInfos[name] = eventInfo;
}
else
{
if (list.Count > 0)
break;
}
#endregion
list.Add(eventInfo);
}
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe RuntimePropertyInfo[] PopulateProperties(Filter filter)
{
Contract.Requires(ReflectedType != null);
// m_csMemberInfos can be null at this point. It will be initialized when Insert
// is called in Populate after this returns.
RuntimeType declaringType = ReflectedType;
Contract.Assert(declaringType != null);
ListBuilder<RuntimePropertyInfo> list = new ListBuilder<RuntimePropertyInfo>();
if (!RuntimeTypeHandle.IsInterface(declaringType))
{
while(RuntimeTypeHandle.IsGenericVariable(declaringType))
declaringType = declaringType.GetBaseType();
// Do not create the dictionary if we are filtering the properties by name already
Dictionary<String, List<RuntimePropertyInfo>> csPropertyInfos = filter.CaseSensitive() ? null :
new Dictionary<String, List<RuntimePropertyInfo>>();
// All elements automatically initialized to false.
bool[] usedSlots = new bool[RuntimeTypeHandle.GetNumVirtuals(declaringType)];
// Populate associates off of the class hierarchy
do
{
PopulateProperties(filter, declaringType, csPropertyInfos, usedSlots, ref list);
declaringType = RuntimeTypeHandle.GetBaseType(declaringType);
} while (declaringType != null);
}
else
{
// Populate associates for this interface
PopulateProperties(filter, declaringType, null, null, ref list);
}
return list.ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
private unsafe void PopulateProperties(
Filter filter,
RuntimeType declaringType,
Dictionary<String, List<RuntimePropertyInfo>> csPropertyInfos,
bool[] usedSlots,
ref ListBuilder<RuntimePropertyInfo> list)
{
int tkDeclaringType = RuntimeTypeHandle.GetToken(declaringType);
// Arrays, Pointers, ByRef types and others generated only the fly by the RT do not have tokens.
if (MdToken.IsNullToken(tkDeclaringType))
return;
MetadataImport scope = RuntimeTypeHandle.GetMetadataImport(declaringType);
MetadataEnumResult tkProperties;
scope.EnumProperties(tkDeclaringType, out tkProperties);
RuntimeModule declaringModuleHandle = RuntimeTypeHandle.GetModule(declaringType);
int numVirtuals = RuntimeTypeHandle.GetNumVirtuals(declaringType);
Contract.Assert((declaringType.IsInterface && usedSlots == null && csPropertyInfos == null) ||
(!declaringType.IsInterface && usedSlots != null && usedSlots.Length >= numVirtuals));
for (int i = 0; i < tkProperties.Length; i++)
{
int tkProperty = tkProperties[i];
bool isPrivate;
Contract.Assert(!MdToken.IsNullToken(tkProperty));
Contract.Assert(MdToken.IsTokenOfType(tkProperty, MetadataTokenType.Property));
if (filter.RequiresStringComparison())
{
if (!ModuleHandle.ContainsPropertyMatchingHash(declaringModuleHandle, tkProperty, filter.GetHashToMatch()))
{
Contract.Assert(!filter.Match(declaringType.GetRuntimeModule().MetadataImport.GetName(tkProperty)));
continue;
}
Utf8String name;
name = declaringType.GetRuntimeModule().MetadataImport.GetName(tkProperty);
if (!filter.Match(name))
continue;
}
RuntimePropertyInfo propertyInfo =
new RuntimePropertyInfo(
tkProperty, declaringType, m_runtimeTypeCache, out isPrivate);
// If this is a class, not an interface
if (usedSlots != null)
{
#region Remove Privates
if (declaringType != ReflectedType && isPrivate)
continue;
#endregion
#region Duplicate check based on vtable slots
// The inheritance of properties are defined by the inheritance of their
// getters and setters.
// A property on a base type is "overriden" by a property on a sub type
// if the getter/setter of the latter occupies the same vtable slot as
// the getter/setter of the former.
MethodInfo associateMethod = propertyInfo.GetGetMethod();
if (associateMethod == null)
{
// We only need to examine the setter if a getter doesn't exist.
// It is not logical for the getter to be virtual but not the setter.
associateMethod = propertyInfo.GetSetMethod();
}
if (associateMethod != null)
{
int slot = RuntimeMethodHandle.GetSlot((RuntimeMethodInfo)associateMethod);
if (slot < numVirtuals)
{
Contract.Assert(associateMethod.IsVirtual);
if (usedSlots[slot] == true)
continue;
else
usedSlots[slot] = true;
}
}
#endregion
#region Duplicate check based on name and signature
// For backward compatibility, even if the vtable slots don't match, we will still treat
// a property as duplicate if the names and signatures match.
if (csPropertyInfos != null)
{
string name = propertyInfo.Name;
List<RuntimePropertyInfo> cache = csPropertyInfos.GetValueOrDefault(name);
if (cache == null)
{
cache = new List<RuntimePropertyInfo>(1);
csPropertyInfos[name] = cache;
}
for (int j = 0; j < cache.Count; j++)
{
if (propertyInfo.EqualsSig(cache[j]))
{
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && !propertyInfo.HasMatchingAccessibility(cache[j]))
{
InitializeAndUpdateAmbiguousPropertiesList(propertyInfo, cache[j]);
}
else
#endif
{
cache = null;
break;
}
}
}
if (cache == null)
continue;
cache.Add(propertyInfo);
}
else
{
bool duplicate = false;
for (int j = 0; j < list.Count; j++)
{
if (propertyInfo.EqualsSig(list[j]))
{
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && !propertyInfo.HasMatchingAccessibility(list[j]))
{
InitializeAndUpdateAmbiguousPropertiesList(propertyInfo, list[j]);
}
else
#endif
{
duplicate = true;
break;
}
}
}
if (duplicate)
continue;
}
#endregion
}
list.Add(propertyInfo);
}
}
#endregion
#region NonPrivate Members
internal T[] GetMemberList(MemberListType listType, string name, CacheType cacheType)
{
T[] list = null;
switch(listType)
{
case MemberListType.CaseSensitive:
list = m_csMemberInfos[name];
if (list != null)
return list;
return Populate(name, listType, cacheType);
case MemberListType.CaseInsensitive:
list = m_cisMemberInfos[name];
if (list != null)
return list;
return Populate(name, listType, cacheType);
default:
Contract.Assert(listType == MemberListType.All);
if (Volatile.Read(ref m_cacheComplete))
return m_allMembers;
return Populate(null, listType, cacheType);
}
}
internal RuntimeType ReflectedType
{
get
{
return m_runtimeTypeCache.GetRuntimeType();
}
}
#endregion
}
#endregion
#region Private Data Members
private RuntimeType m_runtimeType;
private RuntimeType m_enclosingType;
private TypeCode m_typeCode;
private string m_name;
private string m_fullname;
private string m_toString;
private string m_namespace;
private string m_serializationname;
private bool m_isGlobal;
private bool m_bIsDomainInitialized;
private MemberInfoCache<RuntimeMethodInfo> m_methodInfoCache;
private MemberInfoCache<RuntimeConstructorInfo> m_constructorInfoCache;
private MemberInfoCache<RuntimeFieldInfo> m_fieldInfoCache;
private MemberInfoCache<RuntimeType> m_interfaceCache;
private MemberInfoCache<RuntimeType> m_nestedClassesCache;
private MemberInfoCache<RuntimePropertyInfo> m_propertyInfoCache;
private MemberInfoCache<RuntimeEventInfo> m_eventInfoCache;
private static CerHashtable<RuntimeMethodInfo, RuntimeMethodInfo> s_methodInstantiations;
private static Object s_methodInstantiationsLock;
#if !FEATURE_CORECLR
private RuntimeConstructorInfo m_serializationCtor;
#endif
private string m_defaultMemberName;
private Object m_genericCache; // Generic cache for rare scenario specific data. It is used to cache Enum names and values.
#endregion
#region Constructor
internal RuntimeTypeCache(RuntimeType runtimeType)
{
m_typeCode = TypeCode.Empty;
m_runtimeType = runtimeType;
m_isGlobal = RuntimeTypeHandle.GetModule(runtimeType).RuntimeType == runtimeType;
}
#endregion
#region Private Members
private string ConstructName(ref string name, TypeNameFormatFlags formatFlags)
{
if (name == null)
{
name = new RuntimeTypeHandle(m_runtimeType).ConstructName(formatFlags);
}
return name;
}
private T[] GetMemberList<T>(ref MemberInfoCache<T> m_cache, MemberListType listType, string name, CacheType cacheType)
where T : MemberInfo
{
MemberInfoCache<T> existingCache = GetMemberCache<T>(ref m_cache);
return existingCache.GetMemberList(listType, name, cacheType);
}
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
private T[] GetMemberList<T>(ref MemberInfoCache<T> m_cache, MemberListType listType, string name, CacheType cacheType, out IReadOnlyList<RuntimePropertyInfo> ambiguousProperties)
where T : MemberInfo
{
Contract.Assert(cacheType == CacheType.Property);
MemberInfoCache<T> existingCache = GetMemberCache<T>(ref m_cache);
T[] results = existingCache.GetMemberList(listType, name, cacheType);
// must access property after GetMemberList() has been called
ambiguousProperties = existingCache.AmbiguousProperties;
// we should only have an ambiguous properties list in Mango-compat mode
Contract.Assert(ambiguousProperties == null || CompatibilitySwitches.IsAppEarlierThanWindowsPhone8);
return results;
}
#endif
private MemberInfoCache<T> GetMemberCache<T>(ref MemberInfoCache<T> m_cache)
where T : MemberInfo
{
MemberInfoCache<T> existingCache = m_cache;
if (existingCache == null)
{
MemberInfoCache<T> newCache = new MemberInfoCache<T>(this);
existingCache = Interlocked.CompareExchange(ref m_cache, newCache, null);
if (existingCache == null)
existingCache = newCache;
}
return existingCache;
}
#endregion
#region Internal Members
internal Object GenericCache
{
get { return m_genericCache; }
set { m_genericCache = value; }
}
internal bool DomainInitialized
{
get { return m_bIsDomainInitialized; }
set { m_bIsDomainInitialized = value; }
}
internal string GetName(TypeNameKind kind)
{
switch (kind)
{
case TypeNameKind.Name:
// No namespace, full instantiation, and assembly.
return ConstructName(ref m_name, TypeNameFormatFlags.FormatBasic);
case TypeNameKind.FullName:
// We exclude the types that contain generic parameters because their names cannot be roundtripped.
// We allow generic type definitions (and their refs, ptrs, and arrays) because their names can be roundtriped.
// Theoretically generic types instantiated with generic type definitions can be roundtripped, e.g. List`1<Dictionary`2>.
// But these kind of types are useless, rare, and hard to identity. We would need to recursively examine all the
// generic arguments with the same criteria. We will exclude them unless we see a real user scenario.
if (!m_runtimeType.GetRootElementType().IsGenericTypeDefinition && m_runtimeType.ContainsGenericParameters)
return null;
// No assembly.
return ConstructName(ref m_fullname, TypeNameFormatFlags.FormatNamespace | TypeNameFormatFlags.FormatFullInst);
case TypeNameKind.ToString:
// No full instantiation and assembly.
return ConstructName(ref m_toString, TypeNameFormatFlags.FormatNamespace);
case TypeNameKind.SerializationName:
// Use FormatGenericParam in serialization. Otherwise we won't be able
// to distinguish between a generic parameter and a normal type with the same name.
// e.g. Foo<T>.Bar(T t), the parameter type T could be !1 or a real type named "T".
// Excluding the version number in the assembly name for VTS.
return ConstructName(ref m_serializationname, TypeNameFormatFlags.FormatSerialization);
default:
throw new InvalidOperationException();
}
}
[System.Security.SecuritySafeCritical]
internal unsafe string GetNameSpace()
{
// @Optimization - Use ConstructName to populate m_namespace
if (m_namespace == null)
{
Type type = m_runtimeType;
type = type.GetRootElementType();
while (type.IsNested)
type = type.DeclaringType;
m_namespace = RuntimeTypeHandle.GetMetadataImport((RuntimeType)type).GetNamespace(type.MetadataToken).ToString();
}
return m_namespace;
}
internal TypeCode TypeCode
{
get { return m_typeCode; }
set { m_typeCode = value; }
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe RuntimeType GetEnclosingType()
{
if (m_enclosingType == null)
{
// Use void as a marker of null enclosing type
RuntimeType enclosingType = RuntimeTypeHandle.GetDeclaringType(GetRuntimeType());
Contract.Assert(enclosingType != typeof(void));
m_enclosingType = enclosingType ?? (RuntimeType)typeof(void);
}
return (m_enclosingType == typeof(void)) ? null : m_enclosingType;
}
internal RuntimeType GetRuntimeType()
{
return m_runtimeType;
}
internal bool IsGlobal
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get { return m_isGlobal; }
}
internal void InvalidateCachedNestedType()
{
m_nestedClassesCache = null;
}
#if !FEATURE_CORECLR
internal RuntimeConstructorInfo GetSerializationCtor()
{
if (m_serializationCtor == null)
{
if (s_SICtorParamTypes == null)
s_SICtorParamTypes = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
m_serializationCtor = m_runtimeType.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null,
CallingConventions.Any,
s_SICtorParamTypes,
null) as RuntimeConstructorInfo;
}
return m_serializationCtor;
}
#endif //!FEATURE_CORECLR
internal string GetDefaultMemberName()
{
if (m_defaultMemberName == null)
{
CustomAttributeData attr = null;
Type DefaultMemberAttrType = typeof(DefaultMemberAttribute);
for (RuntimeType t = m_runtimeType; t != null; t = t.GetBaseType())
{
IList<CustomAttributeData> attrs = CustomAttributeData.GetCustomAttributes(t);
for (int i = 0; i < attrs.Count; i++)
{
if (Object.ReferenceEquals(attrs[i].Constructor.DeclaringType, DefaultMemberAttrType))
{
attr = attrs[i];
break;
}
}
if (attr != null)
{
m_defaultMemberName = attr.ConstructorArguments[0].Value as string;
break;
}
}
}
return m_defaultMemberName;
}
#endregion
#region Caches Accessors
[System.Security.SecurityCritical] // auto-generated
internal MethodInfo GetGenericMethodInfo(RuntimeMethodHandleInternal genericMethod)
{
LoaderAllocator la = RuntimeMethodHandle.GetLoaderAllocator(genericMethod);
RuntimeMethodInfo rmi = new RuntimeMethodInfo(
genericMethod, RuntimeMethodHandle.GetDeclaringType(genericMethod), this,
RuntimeMethodHandle.GetAttributes(genericMethod), (BindingFlags)(-1), la);
RuntimeMethodInfo crmi;
if (la != null)
{
crmi = la.m_methodInstantiations[rmi];
}
else
{
crmi = s_methodInstantiations[rmi];
}
if (crmi != null)
return crmi;
if (s_methodInstantiationsLock == null)
Interlocked.CompareExchange(ref s_methodInstantiationsLock, new Object(), null);
bool lockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(s_methodInstantiationsLock, ref lockTaken);
if (la != null)
{
crmi = la.m_methodInstantiations[rmi];
if (crmi != null)
return crmi;
la.m_methodInstantiations[rmi] = rmi;
}
else
{
crmi = s_methodInstantiations[rmi];
if (crmi != null)
return crmi;
s_methodInstantiations[rmi] = rmi;
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(s_methodInstantiationsLock);
}
}
return rmi;
}
internal RuntimeMethodInfo[] GetMethodList(MemberListType listType, string name)
{
return GetMemberList<RuntimeMethodInfo>(ref m_methodInfoCache, listType, name, CacheType.Method);
}
internal RuntimeConstructorInfo[] GetConstructorList(MemberListType listType, string name)
{
return GetMemberList<RuntimeConstructorInfo>(ref m_constructorInfoCache, listType, name, CacheType.Constructor);
}
internal RuntimePropertyInfo[] GetPropertyList(MemberListType listType, string name)
{
return GetMemberList<RuntimePropertyInfo>(ref m_propertyInfoCache, listType, name, CacheType.Property);
}
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
internal RuntimePropertyInfo[] GetPropertyList(MemberListType listType, string name, out IReadOnlyList<RuntimePropertyInfo> ambiguousProperties)
{
return GetMemberList<RuntimePropertyInfo>(ref m_propertyInfoCache, listType, name, CacheType.Property, out ambiguousProperties);
}
#endif
internal RuntimeEventInfo[] GetEventList(MemberListType listType, string name)
{
return GetMemberList<RuntimeEventInfo>(ref m_eventInfoCache, listType, name, CacheType.Event);
}
internal RuntimeFieldInfo[] GetFieldList(MemberListType listType, string name)
{
return GetMemberList<RuntimeFieldInfo>(ref m_fieldInfoCache, listType, name, CacheType.Field);
}
internal RuntimeType[] GetInterfaceList(MemberListType listType, string name)
{
return GetMemberList<RuntimeType>(ref m_interfaceCache, listType, name, CacheType.Interface);
}
internal RuntimeType[] GetNestedTypeList(MemberListType listType, string name)
{
return GetMemberList<RuntimeType>(ref m_nestedClassesCache, listType, name, CacheType.NestedType);
}
internal MethodBase GetMethod(RuntimeType declaringType, RuntimeMethodHandleInternal method)
{
GetMemberCache<RuntimeMethodInfo>(ref m_methodInfoCache);
return m_methodInfoCache.AddMethod(declaringType, method, CacheType.Method);
}
internal MethodBase GetConstructor(RuntimeType declaringType, RuntimeMethodHandleInternal constructor)
{
GetMemberCache<RuntimeConstructorInfo>(ref m_constructorInfoCache);
return m_constructorInfoCache.AddMethod(declaringType, constructor, CacheType.Constructor);
}
internal FieldInfo GetField(RuntimeFieldHandleInternal field)
{
GetMemberCache<RuntimeFieldInfo>(ref m_fieldInfoCache);
return m_fieldInfoCache.AddField(field);
}
#endregion
}
#endregion
#if FEATURE_REMOTING
#region Legacy Remoting Cache
// The size of CachedData is accounted for by BaseObjectWithCachedData in object.h.
// This member is currently being used by Remoting for caching remoting data. If you
// need to cache data here, talk to the Remoting team to work out a mechanism, so that
// both caching systems can happily work together.
private RemotingTypeCachedData m_cachedData;
internal RemotingTypeCachedData RemotingCache
{
get
{
// This grabs an internal copy of m_cachedData and uses
// that instead of looking at m_cachedData directly because
// the cache may get cleared asynchronously. This prevents
// us from having to take a lock.
RemotingTypeCachedData cache = m_cachedData;
if (cache == null)
{
cache = new RemotingTypeCachedData(this);
RemotingTypeCachedData ret = Interlocked.CompareExchange(ref m_cachedData, cache, null);
if (ret != null)
cache = ret;
}
return cache;
}
}
#endregion
#endif //FEATURE_REMOTING
#region Static Members
#region Internal
internal static RuntimeType GetType(String typeName, bool throwOnError, bool ignoreCase, bool reflectionOnly,
ref StackCrawlMark stackMark)
{
if (typeName == null)
throw new ArgumentNullException("typeName");
Contract.EndContractBlock();
#if FEATURE_LEGACYNETCF
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && typeName.Length == 0)
throw new TypeLoadException(Environment.GetResourceString("Arg_TypeLoadNullStr"));
#endif
return RuntimeTypeHandle.GetTypeByName(
typeName, throwOnError, ignoreCase, reflectionOnly, ref stackMark, false);
}
internal static MethodBase GetMethodBase(RuntimeModule scope, int typeMetadataToken)
{
return GetMethodBase(ModuleHandle.ResolveMethodHandleInternal(scope, typeMetadataToken));
}
internal static MethodBase GetMethodBase(IRuntimeMethodInfo methodHandle)
{
return GetMethodBase(null, methodHandle);
}
[System.Security.SecuritySafeCritical]
internal static MethodBase GetMethodBase(RuntimeType reflectedType, IRuntimeMethodInfo methodHandle)
{
MethodBase retval = RuntimeType.GetMethodBase(reflectedType, methodHandle.Value);
GC.KeepAlive(methodHandle);
return retval;
}
[System.Security.SecurityCritical] // auto-generated
internal unsafe static MethodBase GetMethodBase(RuntimeType reflectedType, RuntimeMethodHandleInternal methodHandle)
{
Contract.Assert(!methodHandle.IsNullHandle());
if (RuntimeMethodHandle.IsDynamicMethod(methodHandle))
{
Resolver resolver = RuntimeMethodHandle.GetResolver(methodHandle);
if (resolver != null)
return resolver.GetDynamicMethod();
return null;
}
// verify the type/method relationship
RuntimeType declaredType = RuntimeMethodHandle.GetDeclaringType(methodHandle);
RuntimeType[] methodInstantiation = null;
if (reflectedType == null)
reflectedType = declaredType as RuntimeType;
if (reflectedType != declaredType && !reflectedType.IsSubclassOf(declaredType))
{
// object[] is assignable from string[].
if (reflectedType.IsArray)
{
//
// The whole purpose of this chunk of code is not only for error checking.
// GetMember has a side effect of populating the member cache of reflectedType,
// doing so will ensure we construct the correct MethodInfo/ConstructorInfo objects.
// Without this the reflectedType.Cache.GetMethod call below may return a MethodInfo
// object whose ReflectedType is string[] and DeclaringType is object[]. That would
// be (arguabally) incorrect because string[] is not a subclass of object[].
MethodBase[] methodBases = reflectedType.GetMember(
RuntimeMethodHandle.GetName(methodHandle), MemberTypes.Constructor | MemberTypes.Method,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) as MethodBase[];
bool loaderAssuredCompatible = false;
for (int i = 0; i < methodBases.Length; i++)
{
IRuntimeMethodInfo rmi = (IRuntimeMethodInfo)methodBases[i];
if (rmi.Value.Value == methodHandle.Value)
loaderAssuredCompatible = true;
}
if (!loaderAssuredCompatible)
throw new ArgumentException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_ResolveMethodHandle"),
reflectedType.ToString(), declaredType.ToString()));
}
// Action<in string> is assignable from, but not a subclass of Action<in object>.
else if (declaredType.IsGenericType)
{
// ignoring instantiation is the ReflectedType a subtype of the DeclaringType
RuntimeType declaringDefinition = (RuntimeType)declaredType.GetGenericTypeDefinition();
RuntimeType baseType = reflectedType;
while (baseType != null)
{
RuntimeType baseDefinition = baseType;
if (baseDefinition.IsGenericType && !baseType.IsGenericTypeDefinition)
baseDefinition = (RuntimeType)baseDefinition.GetGenericTypeDefinition();
if (baseDefinition == declaringDefinition)
break;
baseType = baseType.GetBaseType();
}
if (baseType == null)
{
// ignoring instantiation is the ReflectedType is not a subtype of the DeclaringType
throw new ArgumentException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_ResolveMethodHandle"),
reflectedType.ToString(), declaredType.ToString()));
}
// remap the method to same method on the subclass ReflectedType
declaredType = baseType;
// if the original methodHandle was the definition then we don't need to rebind generic method arguments
// because all RuntimeMethodHandles retrieved off of the canonical method table are definitions. That's
// why for everything else we need to rebind the generic method arguments.
if (!RuntimeMethodHandle.IsGenericMethodDefinition(methodHandle))
{
methodInstantiation = RuntimeMethodHandle.GetMethodInstantiationInternal(methodHandle);
}
// lookup via v-table slot the RuntimeMethodHandle on the new declaring type
methodHandle = RuntimeMethodHandle.GetMethodFromCanonical(methodHandle, declaredType);
}
else if (!declaredType.IsAssignableFrom(reflectedType))
{
// declaredType is not Array, not generic, and not assignable from reflectedType
throw new ArgumentException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_ResolveMethodHandle"),
reflectedType.ToString(), declaredType.ToString()));
}
}
// If methodInstantiation is not null, GetStubIfNeeded will rebind the generic method arguments
// if declaredType is an instantiated generic type and methodHandle is not generic, get the instantiated MethodDesc (if needed)
// if declaredType is a value type, get the unboxing stub (if needed)
// this is so that our behavior here is consistent with that of Type.GetMethod
// See MemberInfoCache<RuntimeConstructorInfo>.PopulateMethods and MemberInfoCache<RuntimeMethodInfoInfo>.PopulateConstructors
methodHandle = RuntimeMethodHandle.GetStubIfNeeded(methodHandle, declaredType, methodInstantiation);
MethodBase retval;
if (RuntimeMethodHandle.IsConstructor(methodHandle))
{
// Constructor case: constructors cannot be generic
retval = reflectedType.Cache.GetConstructor(declaredType, methodHandle);
}
else
{
// Method case
if (RuntimeMethodHandle.HasMethodInstantiation(methodHandle) && !RuntimeMethodHandle.IsGenericMethodDefinition(methodHandle))
retval = reflectedType.Cache.GetGenericMethodInfo(methodHandle);
else
retval = reflectedType.Cache.GetMethod(declaredType, methodHandle);
}
GC.KeepAlive(methodInstantiation);
return retval;
}
internal Object GenericCache
{
get { return Cache.GenericCache; }
set { Cache.GenericCache = value; }
}
internal bool DomainInitialized
{
get { return Cache.DomainInitialized; }
set { Cache.DomainInitialized = value; }
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe static FieldInfo GetFieldInfo(IRuntimeFieldInfo fieldHandle)
{
return GetFieldInfo(RuntimeFieldHandle.GetApproxDeclaringType(fieldHandle), fieldHandle);
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe static FieldInfo GetFieldInfo(RuntimeType reflectedType, IRuntimeFieldInfo field)
{
RuntimeFieldHandleInternal fieldHandle = field.Value;
// verify the type/method relationship
if (reflectedType == null)
{
reflectedType = RuntimeFieldHandle.GetApproxDeclaringType(fieldHandle);
}
else
{
RuntimeType declaredType = RuntimeFieldHandle.GetApproxDeclaringType(fieldHandle);
if (reflectedType != declaredType)
{
if (!RuntimeFieldHandle.AcquiresContextFromThis(fieldHandle) ||
!RuntimeTypeHandle.CompareCanonicalHandles(declaredType, reflectedType))
{
throw new ArgumentException(String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_ResolveFieldHandle"),
reflectedType.ToString(),
declaredType.ToString()));
}
}
}
FieldInfo retVal = reflectedType.Cache.GetField(fieldHandle);
GC.KeepAlive(field);
return retVal;
}
// Called internally
private unsafe static PropertyInfo GetPropertyInfo(RuntimeType reflectedType, int tkProperty)
{
RuntimePropertyInfo property = null;
RuntimePropertyInfo[] candidates =
reflectedType.Cache.GetPropertyList(MemberListType.All, null);
for (int i = 0; i < candidates.Length; i++)
{
property = candidates[i];
if (property.MetadataToken == tkProperty)
return property;
}
Contract.Assume(false, "Unreachable code");
throw new SystemException();
}
private static void ThrowIfTypeNeverValidGenericArgument(RuntimeType type)
{
if (type.IsPointer || type.IsByRef || type == typeof(void))
throw new ArgumentException(
Environment.GetResourceString("Argument_NeverValidGenericArgument", type.ToString()));
}
internal static void SanityCheckGenericArguments(RuntimeType[] genericArguments, RuntimeType[] genericParamters)
{
if (genericArguments == null)
throw new ArgumentNullException();
Contract.EndContractBlock();
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(
Environment.GetResourceString("Argument_NotEnoughGenArguments", genericArguments.Length, genericParamters.Length));
}
[System.Security.SecuritySafeCritical] // auto-generated
internal static void ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
{
RuntimeType[] typeContext = null;
RuntimeType[] methodContext = null;
RuntimeType[] genericParamters = null;
if (definition is Type)
{
RuntimeType genericTypeDefinition = (RuntimeType)definition;
genericParamters = genericTypeDefinition.GetGenericArgumentsInternal();
typeContext = genericArguments;
}
else
{
RuntimeMethodInfo genericMethodDefinition = (RuntimeMethodInfo)definition;
genericParamters = genericMethodDefinition.GetGenericArgumentsInternal();
methodContext = genericArguments;
RuntimeType declaringType = (RuntimeType)genericMethodDefinition.DeclaringType;
if (declaringType != null)
{
typeContext = declaringType.GetTypeHandleInternal().GetInstantiationInternal();
}
}
for (int i = 0; i < genericArguments.Length; i++)
{
Type genericArgument = genericArguments[i];
Type genericParameter = genericParamters[i];
if (!RuntimeTypeHandle.SatisfiesConstraints(genericParameter.GetTypeHandleInternal().GetTypeChecked(),
typeContext, methodContext, genericArgument.GetTypeHandleInternal().GetTypeChecked()))
{
throw new ArgumentException(
Environment.GetResourceString("Argument_GenConstraintViolation",
i.ToString(CultureInfo.CurrentCulture), genericArgument.ToString(), definition.ToString(), genericParameter.ToString()), e);
}
}
}
private static void SplitName(string fullname, out string name, out string ns)
{
name = null;
ns = null;
if (fullname == null)
return;
// Get namespace
int nsDelimiter = fullname.LastIndexOf(".", StringComparison.Ordinal);
if (nsDelimiter != -1 )
{
ns = fullname.Substring(0, nsDelimiter);
int nameLength = fullname.Length - ns.Length - 1;
if (nameLength != 0)
name = fullname.Substring(nsDelimiter + 1, nameLength);
else
name = "";
Contract.Assert(fullname.Equals(ns + "." + name));
}
else
{
name = fullname;
}
}
#endregion
#region Filters
internal static BindingFlags FilterPreCalculate(bool isPublic, bool isInherited, bool isStatic)
{
BindingFlags bindingFlags = isPublic ? BindingFlags.Public : BindingFlags.NonPublic;
if (isInherited)
{
// We arrange things so the DeclaredOnly flag means "include inherited members"
bindingFlags |= BindingFlags.DeclaredOnly;
if (isStatic)
{
bindingFlags |= BindingFlags.Static | BindingFlags.FlattenHierarchy;
}
else
{
bindingFlags |= BindingFlags.Instance;
}
}
else
{
if (isStatic)
{
bindingFlags |= BindingFlags.Static;
}
else
{
bindingFlags |= BindingFlags.Instance;
}
}
return bindingFlags;
}
// Calculate prefixLookup, ignoreCase, and listType for use by GetXXXCandidates
private static void FilterHelper(
BindingFlags bindingFlags, ref string name, bool allowPrefixLookup, out bool prefixLookup,
out bool ignoreCase, out MemberListType listType)
{
prefixLookup = false;
ignoreCase = false;
if (name != null)
{
if ((bindingFlags & BindingFlags.IgnoreCase) != 0)
{
name = name.ToLower(CultureInfo.InvariantCulture);
ignoreCase = true;
listType = MemberListType.CaseInsensitive;
}
else
{
listType = MemberListType.CaseSensitive;
}
if (allowPrefixLookup && name.EndsWith("*", StringComparison.Ordinal))
{
// We set prefixLookup to true if name ends with a "*".
// We will also set listType to All so that all members are included in
// the candidates which are later filtered by FilterApplyPrefixLookup.
name = name.Substring(0, name.Length - 1);
prefixLookup = true;
listType = MemberListType.All;
}
}
else
{
listType = MemberListType.All;
}
}
// Used by the singular GetXXX APIs (Event, Field, Interface, NestedType) where prefixLookup is not supported.
private static void FilterHelper(BindingFlags bindingFlags, ref string name, out bool ignoreCase, out MemberListType listType)
{
bool prefixLookup;
FilterHelper(bindingFlags, ref name, false, out prefixLookup, out ignoreCase, out listType);
}
// Only called by GetXXXCandidates, GetInterfaces, and GetNestedTypes when FilterHelper has set "prefixLookup" to true.
// Most of the plural GetXXX methods allow prefix lookups while the singular GetXXX methods mostly do not.
private static bool FilterApplyPrefixLookup(MemberInfo memberInfo, string name, bool ignoreCase)
{
Contract.Assert(name != null);
if (ignoreCase)
{
if (!memberInfo.Name.StartsWith(name, StringComparison.OrdinalIgnoreCase))
return false;
}
else
{
if (!memberInfo.Name.StartsWith(name, StringComparison.Ordinal))
return false;
}
return true;
}
// Used by FilterApplyType to perform all the filtering based on name and BindingFlags
private static bool FilterApplyBase(
MemberInfo memberInfo, BindingFlags bindingFlags, bool isPublic, bool isNonProtectedInternal, bool isStatic,
string name, bool prefixLookup)
{
#region Preconditions
Contract.Requires(memberInfo != null);
Contract.Requires(name == null || (bindingFlags & BindingFlags.IgnoreCase) == 0 || (name.ToLower(CultureInfo.InvariantCulture).Equals(name)));
#endregion
#region Filter by Public & Private
if (isPublic)
{
if ((bindingFlags & BindingFlags.Public) == 0)
return false;
}
else
{
if ((bindingFlags & BindingFlags.NonPublic) == 0)
return false;
}
#endregion
bool isInherited = !Object.ReferenceEquals(memberInfo.DeclaringType, memberInfo.ReflectedType);
#region Filter by DeclaredOnly
if ((bindingFlags & BindingFlags.DeclaredOnly) != 0 && isInherited)
return false;
#endregion
#region Filter by Static & Instance
if (memberInfo.MemberType != MemberTypes.TypeInfo &&
memberInfo.MemberType != MemberTypes.NestedType)
{
if (isStatic)
{
if ((bindingFlags & BindingFlags.FlattenHierarchy) == 0 && isInherited)
return false;
if ((bindingFlags & BindingFlags.Static) == 0)
return false;
}
else
{
if ((bindingFlags & BindingFlags.Instance) == 0)
return false;
}
}
#endregion
#region Filter by name wrt prefixLookup and implicitly by case sensitivity
if (prefixLookup == true)
{
if (!FilterApplyPrefixLookup(memberInfo, name, (bindingFlags & BindingFlags.IgnoreCase) != 0))
return false;
}
#endregion
#region Asymmetries
// @Asymmetry - Internal, inherited, instance, non-protected, non-virtual, non-abstract members returned
// iff BindingFlags !DeclaredOnly, Instance and Public are present except for fields
if (((bindingFlags & BindingFlags.DeclaredOnly) == 0) && // DeclaredOnly not present
isInherited && // Is inherited Member
(isNonProtectedInternal) && // Is non-protected internal member
((bindingFlags & BindingFlags.NonPublic) != 0) && // BindingFlag.NonPublic present
(!isStatic) && // Is instance member
((bindingFlags & BindingFlags.Instance) != 0)) // BindingFlag.Instance present
{
MethodInfo methodInfo = memberInfo as MethodInfo;
if (methodInfo == null)
return false;
if (!methodInfo.IsVirtual && !methodInfo.IsAbstract)
return false;
}
#endregion
return true;
}
// Used by GetInterface and GetNestedType(s) which don't need parameter type filtering.
private static bool FilterApplyType(
Type type, BindingFlags bindingFlags, string name, bool prefixLookup, string ns)
{
Contract.Requires((object)type != null);
Contract.Assert(type is RuntimeType);
bool isPublic = type.IsNestedPublic || type.IsPublic;
bool isStatic = false;
if (!RuntimeType.FilterApplyBase(type, bindingFlags, isPublic, type.IsNestedAssembly, isStatic, name, prefixLookup))
return false;
if (ns != null && !type.Namespace.Equals(ns))
return false;
return true;
}
private static bool FilterApplyMethodInfo(
RuntimeMethodInfo method, BindingFlags bindingFlags, CallingConventions callConv, Type[] argumentTypes)
{
// Optimization: Pre-Calculate the method binding flags to avoid casting.
return FilterApplyMethodBase(method, method.BindingFlags, bindingFlags, callConv, argumentTypes);
}
private static bool FilterApplyConstructorInfo(
RuntimeConstructorInfo constructor, BindingFlags bindingFlags, CallingConventions callConv, Type[] argumentTypes)
{
// Optimization: Pre-Calculate the method binding flags to avoid casting.
return FilterApplyMethodBase(constructor, constructor.BindingFlags, bindingFlags, callConv, argumentTypes);
}
// 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;
}
#endregion
#endregion
#region Private Data Members
private object m_keepalive; // This will be filled with a LoaderAllocator reference when this RuntimeType represents a collectible type
private IntPtr m_cache;
internal IntPtr m_handle;
#if FEATURE_APPX
private INVOCATION_FLAGS m_invocationFlags;
internal bool IsNonW8PFrameworkAPI()
{
if (IsGenericParameter)
return false;
if (HasElementType)
return ((RuntimeType)GetElementType()).IsNonW8PFrameworkAPI();
if (IsSimpleTypeNonW8PFrameworkAPI())
return true;
if (IsGenericType && !IsGenericTypeDefinition)
{
foreach (Type t in GetGenericArguments())
{
if (((RuntimeType)t).IsNonW8PFrameworkAPI())
return true;
}
}
return false;
}
private bool IsSimpleTypeNonW8PFrameworkAPI()
{
RuntimeAssembly rtAssembly = GetRuntimeAssembly();
if (rtAssembly.IsFrameworkAssembly())
{
int ctorToken = rtAssembly.InvocableAttributeCtorToken;
if (System.Reflection.MetadataToken.IsNullToken(ctorToken) ||
!CustomAttribute.IsAttributeDefined(GetRuntimeModule(), MetadataToken, ctorToken))
return true;
}
return false;
}
internal INVOCATION_FLAGS InvocationFlags
{
get
{
if ((m_invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_INITIALIZED) == 0)
{
INVOCATION_FLAGS invocationFlags = INVOCATION_FLAGS.INVOCATION_FLAGS_UNKNOWN;
if (AppDomain.ProfileAPICheck && IsNonW8PFrameworkAPI())
invocationFlags |= INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API;
m_invocationFlags = invocationFlags | INVOCATION_FLAGS.INVOCATION_FLAGS_INITIALIZED;
}
return m_invocationFlags;
}
}
#endif // FEATURE_APPX
internal static readonly RuntimeType ValueType = (RuntimeType)typeof(System.ValueType);
internal static readonly RuntimeType EnumType = (RuntimeType)typeof(System.Enum);
private static readonly RuntimeType ObjectType = (RuntimeType)typeof(System.Object);
private static readonly RuntimeType StringType = (RuntimeType)typeof(System.String);
private static readonly RuntimeType DelegateType = (RuntimeType)typeof(System.Delegate);
private static Type[] s_SICtorParamTypes;
#endregion
#region Constructor
internal RuntimeType() { throw new NotSupportedException(); }
#endregion
#region Private\Internal Members
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal override bool CacheEquals(object o)
{
RuntimeType m = o as RuntimeType;
if (m == null)
return false;
return m.m_handle.Equals(m_handle);
}
private RuntimeTypeCache Cache
{
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
get
{
if (m_cache.IsNull())
{
IntPtr newgcHandle = new RuntimeTypeHandle(this).GetGCHandle(GCHandleType.WeakTrackResurrection);
IntPtr gcHandle = Interlocked.CompareExchange(ref m_cache, newgcHandle, (IntPtr)0);
// Leak the handle if the type is collectible. It will be reclaimed when
// the type goes away.
if (!gcHandle.IsNull() && !IsCollectible())
GCHandle.InternalFree(newgcHandle);
}
RuntimeTypeCache cache = GCHandle.InternalGet(m_cache) as RuntimeTypeCache;
if (cache == null)
{
cache = new RuntimeTypeCache(this);
RuntimeTypeCache existingCache = GCHandle.InternalCompareExchange(m_cache, cache, null, false) as RuntimeTypeCache;
if (existingCache != null)
cache = existingCache;
}
Contract.Assert(cache != null);
return cache;
}
}
internal bool IsSpecialSerializableType()
{
RuntimeType rt = this;
do
{
// In all sane cases we only need to compare the direct level base type with
// System.Enum and System.MulticastDelegate. However, a generic argument can
// have a base type constraint that is Delegate or even a real delegate type.
// Let's maintain compatibility and return true for them.
if (rt == RuntimeType.DelegateType || rt == RuntimeType.EnumType)
return true;
rt = rt.GetBaseType();
} while (rt != null);
return false;
}
private string GetDefaultMemberName()
{
return Cache.GetDefaultMemberName();
}
#if !FEATURE_CORECLR
internal RuntimeConstructorInfo GetSerializationCtor()
{
return Cache.GetSerializationCtor();
}
#endif
#endregion
#region Type Overrides
#region Get XXXInfo Candidates
private ListBuilder<MethodInfo> GetMethodCandidates(
String name, BindingFlags bindingAttr, CallingConventions callConv,
Type[] types, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
RuntimeMethodInfo[] cache = Cache.GetMethodList(listType, name);
ListBuilder<MethodInfo> candidates = new ListBuilder<MethodInfo>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeMethodInfo methodInfo = cache[i];
if (FilterApplyMethodInfo(methodInfo, bindingAttr, callConv, types) &&
(!prefixLookup || RuntimeType.FilterApplyPrefixLookup(methodInfo, name, ignoreCase)))
{
candidates.Add(methodInfo);
}
}
return candidates;
}
private ListBuilder<ConstructorInfo> GetConstructorCandidates(
string name, BindingFlags bindingAttr, CallingConventions callConv,
Type[] types, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
RuntimeConstructorInfo[] cache = Cache.GetConstructorList(listType, name);
ListBuilder<ConstructorInfo> candidates = new ListBuilder<ConstructorInfo>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeConstructorInfo constructorInfo = cache[i];
if (FilterApplyConstructorInfo(constructorInfo, bindingAttr, callConv, types) &&
(!prefixLookup || RuntimeType.FilterApplyPrefixLookup(constructorInfo, name, ignoreCase)))
{
candidates.Add(constructorInfo);
}
}
return candidates;
}
private ListBuilder<PropertyInfo> GetPropertyCandidates(
String name, BindingFlags bindingAttr, Type[] types, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
IReadOnlyList<RuntimePropertyInfo> ambiguousProperties = null;
RuntimePropertyInfo[] cache = Cache.GetPropertyList(listType, name, out ambiguousProperties);
#else
RuntimePropertyInfo[] cache = Cache.GetPropertyList(listType, name);
#endif
bindingAttr ^= BindingFlags.DeclaredOnly;
ListBuilder<PropertyInfo> candidates = new ListBuilder<PropertyInfo>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimePropertyInfo propertyInfo = cache[i];
if ((bindingAttr & propertyInfo.BindingFlags) == propertyInfo.BindingFlags &&
(!prefixLookup || RuntimeType.FilterApplyPrefixLookup(propertyInfo, name, ignoreCase)) &&
(types == null || (propertyInfo.GetIndexParameters().Length == types.Length)))
{
candidates.Add(propertyInfo);
}
}
#if FEATURE_LEGACYNETCF
// Dev11 466969 quirk
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 &&
candidates.Count > 1 &&
ambiguousProperties != null &&
ambiguousProperties.Count > 0)
{
return PruneAmbiguousProperties(candidates, ambiguousProperties);
}
#endif
return candidates;
}
#if FEATURE_LEGACYNETCF
private ListBuilder<PropertyInfo> PruneAmbiguousProperties(ListBuilder<PropertyInfo> candidates, IReadOnlyList<RuntimePropertyInfo> ambiguousProperties)
{
Contract.Assert(CompatibilitySwitches.IsAppEarlierThanWindowsPhone8);
Contract.Assert(candidates.Count > 1);
Contract.Assert(ambiguousProperties != null && ambiguousProperties.Count > 0);
ListBuilder<PropertyInfo> newCandidates = candidates;
// Dev11 466969 quirk
// NetCF reflection will differentiate properties by sig and by accessibility.
// Consider the following:
//
// class FooBase
// {
// public int Prop { get; set; }
// }
//
// class FooDerived : FooBase
// {
// private int Prop { get; set; }
// }
//
// In Mango one can reflect on FooDerived for property "Prop" with *Public*
// binding flags and get an answer. On desktop CLR/CoreCLR you get back null
// since FooBase.Prop is considered a duplicate and thus removed from the
// list of candidate properties. To make this distinction the method
// RuntimePropertyInfo.HasMatchingAccessibility() was added.
//
// There is a wrinkle here though, when reflecting on FooDerived for
// property "Prop" with Public and NonPublic binding flags the answer
// will always be the most-derived type, so FooDerived in this example.
// The purpose of PruneAmbiguousProperties() is to apply this invariant.
//
int countRemoved = 0;
lock (ambiguousProperties)
{
for (int outerIndex = 0; outerIndex < ambiguousProperties.Count; ++outerIndex)
{
for (int innerIndex = 0; innerIndex < candidates.Count; ++innerIndex)
{
if (candidates[innerIndex] != null &&
candidates[innerIndex] == ambiguousProperties[outerIndex])
{
candidates[innerIndex] = null;
++countRemoved;
}
}
}
}
// should have only gone down this code path because we knew
// that at least one ambiguous property needed to be pruned.
Contract.Assert(countRemoved > 0);
if (countRemoved > 0)
{
newCandidates = new ListBuilder<PropertyInfo>(candidates.Count - countRemoved);
for (int index = 0; index < candidates.Count; ++index)
{
if (candidates[index] != null)
newCandidates.Add(candidates[index]);
}
Contract.Assert(newCandidates.Count == (candidates.Count - countRemoved));
}
return newCandidates;
}
#endif
private ListBuilder<EventInfo> GetEventCandidates(String name, BindingFlags bindingAttr, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
RuntimeEventInfo[] cache = Cache.GetEventList(listType, name);
bindingAttr ^= BindingFlags.DeclaredOnly;
ListBuilder<EventInfo> candidates = new ListBuilder<EventInfo>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeEventInfo eventInfo = cache[i];
if ((bindingAttr & eventInfo.BindingFlags) == eventInfo.BindingFlags &&
(!prefixLookup || RuntimeType.FilterApplyPrefixLookup(eventInfo, name, ignoreCase)))
{
candidates.Add(eventInfo);
}
}
return candidates;
}
private ListBuilder<FieldInfo> GetFieldCandidates(String name, BindingFlags bindingAttr, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
RuntimeFieldInfo[] cache = Cache.GetFieldList(listType, name);
bindingAttr ^= BindingFlags.DeclaredOnly;
ListBuilder<FieldInfo> candidates = new ListBuilder<FieldInfo>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeFieldInfo fieldInfo = cache[i];
if ((bindingAttr & fieldInfo.BindingFlags) == fieldInfo.BindingFlags &&
(!prefixLookup || FilterApplyPrefixLookup(fieldInfo, name, ignoreCase)))
{
candidates.Add(fieldInfo);
}
}
return candidates;
}
private ListBuilder<Type> GetNestedTypeCandidates(String fullname, BindingFlags bindingAttr, bool allowPrefixLookup)
{
bool prefixLookup, ignoreCase;
bindingAttr &= ~BindingFlags.Static;
string name, ns;
MemberListType listType;
SplitName(fullname, out name, out ns);
RuntimeType.FilterHelper(bindingAttr, ref name, allowPrefixLookup, out prefixLookup, out ignoreCase, out listType);
RuntimeType[] cache = Cache.GetNestedTypeList(listType, name);
ListBuilder<Type> candidates = new ListBuilder<Type>(cache.Length);
for (int i = 0; i < cache.Length; i++)
{
RuntimeType nestedClass = cache[i];
if (RuntimeType.FilterApplyType(nestedClass, bindingAttr, name, prefixLookup, ns))
{
candidates.Add(nestedClass);
}
}
return candidates;
}
private class ConstructorInfoComparer : IComparer<ConstructorInfo>
{
internal static readonly ConstructorInfoComparer SortByMetadataToken = new ConstructorInfoComparer();
public Int32 Compare(ConstructorInfo x, ConstructorInfo y)
{
return x.MetadataToken.CompareTo(y.MetadataToken);
}
} // private class ConstructorInfoComparer
#endregion
#region Get All XXXInfos
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
{
return GetMethodCandidates(null, bindingAttr, CallingConventions.Any, null, false).ToArray();
}
[System.Runtime.InteropServices.ComVisible(true)]
public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
{
ConstructorInfo[] constructors = GetConstructorCandidates(null, bindingAttr, CallingConventions.Any, null, false).ToArray();
// Do not use the AppContextSwitch infrastructure as this method is called very early in
// app domain creation. Calling AppContextSwitch may lock the app domain into an undefined
// TargetFramework (eg. 4.0).
if (!IsDoNotForceOrderOfConstructorsSetImpl())
{
// do not consider array types as their MetadataTokens are all the same
// and Array.Sort is not a stable sort. Skip types that are not part of
// ngen'd assemblies to minimize the risk
if (!IsArrayImpl() && IsZappedImpl())
{
// By default sort the returned constructors based on MetadataToken
// which aligns the sort order with MSIL. Assemblies that are ngen'd
// can change the order of the constructors, assemblies that are ngen'd
// with IBC data have a higher chance of changing the order of constructors.
// Avoid using public Array.Sort as that attempts to access BinaryCompatibility. Unfortunately GetConstructors gets called
// very early in the app domain creation, when _FusionStore is not set up yet, resulting in a null TargetFrameworkMoniker being
// set. This then locks in the TargetFrameworkMoniker for the entire process as null.
ArraySortHelper<ConstructorInfo>.IntrospectiveSort(constructors, 0, constructors.Length, ConstructorInfoComparer.SortByMetadataToken);
}
}
return constructors;
}
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
{
return GetPropertyCandidates(null, bindingAttr, null, false).ToArray();
}
public override EventInfo[] GetEvents(BindingFlags bindingAttr)
{
return GetEventCandidates(null, bindingAttr, false).ToArray();
}
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
{
return GetFieldCandidates(null, bindingAttr, false).ToArray();
}
[System.Security.SecuritySafeCritical] // auto-generated
public override Type[] GetInterfaces()
{
RuntimeType[] candidates = this.Cache.GetInterfaceList(MemberListType.All, null);
Type[] interfaces = new Type[candidates.Length];
for (int i = 0; i < candidates.Length; i++)
JitHelpers.UnsafeSetArrayElement(interfaces, i, candidates[i]);
return interfaces;
}
public override Type[] GetNestedTypes(BindingFlags bindingAttr)
{
return GetNestedTypeCandidates(null, bindingAttr, false).ToArray();
}
public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
{
ListBuilder<MethodInfo> methods = GetMethodCandidates(null, bindingAttr, CallingConventions.Any, null, false);
ListBuilder<ConstructorInfo> constructors = GetConstructorCandidates(null, bindingAttr, CallingConventions.Any, null, false);
ListBuilder<PropertyInfo> properties = GetPropertyCandidates(null, bindingAttr, null, false);
ListBuilder<EventInfo> events = GetEventCandidates(null, bindingAttr, false);
ListBuilder<FieldInfo> fields = GetFieldCandidates(null, bindingAttr, false);
ListBuilder<Type> nestedTypes = GetNestedTypeCandidates(null, bindingAttr, false);
// Interfaces are excluded from the result of GetMembers
MemberInfo[] members = new MemberInfo[
methods.Count +
constructors.Count +
properties.Count +
events.Count +
fields.Count +
nestedTypes.Count];
int i = 0;
methods.CopyTo(members, i); i += methods.Count;
constructors.CopyTo(members, i); i += constructors.Count;
properties.CopyTo(members, i); i += properties.Count;
events.CopyTo(members, i); i += events.Count;
fields.CopyTo(members, i); i += fields.Count;
nestedTypes.CopyTo(members, i); i += nestedTypes.Count;
Contract.Assert(i == members.Length);
return members;
}
[System.Security.SecuritySafeCritical] // auto-generated
public override InterfaceMapping GetInterfaceMap(Type ifaceType)
{
if (IsGenericParameter)
throw new InvalidOperationException(Environment.GetResourceString("Arg_GenericParameter"));
if ((object)ifaceType == null)
throw new ArgumentNullException("ifaceType");
Contract.EndContractBlock();
RuntimeType ifaceRtType = ifaceType as RuntimeType;
if (ifaceRtType == null)
throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "ifaceType");
RuntimeTypeHandle ifaceRtTypeHandle = ifaceRtType.GetTypeHandleInternal();
GetTypeHandleInternal().VerifyInterfaceIsImplemented(ifaceRtTypeHandle);
Contract.Assert(ifaceType.IsInterface); // VerifyInterfaceIsImplemented enforces this invariant
Contract.Assert(!IsInterface); // VerifyInterfaceIsImplemented enforces this invariant
// SZArrays implement the methods on IList`1, IEnumerable`1, and ICollection`1 with
// SZArrayHelper and some runtime magic. We don't have accurate interface maps for them.
if (IsSzArray && ifaceType.IsGenericType)
throw new ArgumentException(Environment.GetResourceString("Argument_ArrayGetInterfaceMap"));
int ifaceInstanceMethodCount = RuntimeTypeHandle.GetNumVirtuals(ifaceRtType);
InterfaceMapping im;
im.InterfaceType = ifaceType;
im.TargetType = this;
im.InterfaceMethods = new MethodInfo[ifaceInstanceMethodCount];
im.TargetMethods = new MethodInfo[ifaceInstanceMethodCount];
for (int i = 0; i < ifaceInstanceMethodCount; i++)
{
RuntimeMethodHandleInternal ifaceRtMethodHandle = RuntimeTypeHandle.GetMethodAt(ifaceRtType, i);
// GetMethodBase will convert this to the instantiating/unboxing stub if necessary
MethodBase ifaceMethodBase = RuntimeType.GetMethodBase(ifaceRtType, ifaceRtMethodHandle);
Contract.Assert(ifaceMethodBase is RuntimeMethodInfo);
im.InterfaceMethods[i] = (MethodInfo)ifaceMethodBase;
// If the slot is -1, then virtual stub dispatch is active.
int slot = GetTypeHandleInternal().GetInterfaceMethodImplementationSlot(ifaceRtTypeHandle, ifaceRtMethodHandle);
if (slot == -1) continue;
RuntimeMethodHandleInternal classRtMethodHandle = RuntimeTypeHandle.GetMethodAt(this, slot);
// GetMethodBase will convert this to the instantiating/unboxing stub if necessary
MethodBase rtTypeMethodBase = RuntimeType.GetMethodBase(this, classRtMethodHandle);
// a class may not implement all the methods of an interface (abstract class) so null is a valid value
Contract.Assert(rtTypeMethodBase == null || rtTypeMethodBase is RuntimeMethodInfo);
im.TargetMethods[i] = (MethodInfo)rtTypeMethodBase;
}
return im;
}
#endregion
#region Find XXXInfo
protected override MethodInfo GetMethodImpl(
String name, BindingFlags bindingAttr, Binder binder, CallingConventions callConv,
Type[] types, ParameterModifier[] modifiers)
{
ListBuilder<MethodInfo> candidates = GetMethodCandidates(name, bindingAttr, callConv, types, false);
if (candidates.Count == 0)
return null;
if (types == null || types.Length == 0)
{
MethodInfo firstCandidate = candidates[0];
if (candidates.Count == 1)
{
return firstCandidate;
}
else if (types == null)
{
for (int j = 1; j < candidates.Count; j++)
{
MethodInfo methodInfo = candidates[j];
if (!System.DefaultBinder.CompareMethodSigAndName(methodInfo, firstCandidate))
{
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
}
}
// All the methods have the exact same name and sig so return the most derived one.
return System.DefaultBinder.FindMostDerivedNewSlotMeth(candidates.ToArray(), candidates.Count) as MethodInfo;
}
}
if (binder == null)
binder = DefaultBinder;
return binder.SelectMethod(bindingAttr, candidates.ToArray(), types, modifiers) as MethodInfo;
}
protected override ConstructorInfo GetConstructorImpl(
BindingFlags bindingAttr, Binder binder, CallingConventions callConvention,
Type[] types, ParameterModifier[] modifiers)
{
ListBuilder<ConstructorInfo> candidates = GetConstructorCandidates(null, bindingAttr, CallingConventions.Any, types, false);
if (candidates.Count == 0)
return null;
if (types.Length == 0 && candidates.Count == 1)
{
ConstructorInfo firstCandidate = candidates[0];
ParameterInfo[] parameters = firstCandidate.GetParametersNoCopy();
if (parameters == null || parameters.Length == 0)
{
return firstCandidate;
}
}
if ((bindingAttr & BindingFlags.ExactBinding) != 0)
return System.DefaultBinder.ExactBinding(candidates.ToArray(), types, modifiers) as ConstructorInfo;
if (binder == null)
binder = DefaultBinder;
return binder.SelectMethod(bindingAttr, candidates.ToArray(), types, modifiers) as ConstructorInfo;
}
protected override PropertyInfo GetPropertyImpl(
String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
{
if (name == null) throw new ArgumentNullException();
Contract.EndContractBlock();
ListBuilder<PropertyInfo> candidates = GetPropertyCandidates(name, bindingAttr, types, false);
if (candidates.Count == 0)
return null;
if (types == null || types.Length == 0)
{
// no arguments
if (candidates.Count == 1)
{
PropertyInfo firstCandidate = candidates[0];
if ((object)returnType != null && !returnType.IsEquivalentTo(firstCandidate.PropertyType))
return null;
return firstCandidate;
}
else
{
if ((object)returnType == null)
// if we are here we have no args or property type to select over and we have more than one property with that name
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
}
}
if ((bindingAttr & BindingFlags.ExactBinding) != 0)
return System.DefaultBinder.ExactPropertyBinding(candidates.ToArray(), returnType, types, modifiers);
if (binder == null)
binder = DefaultBinder;
return binder.SelectProperty(bindingAttr, candidates.ToArray(), returnType, types, modifiers);
}
public override EventInfo GetEvent(String name, BindingFlags bindingAttr)
{
if (name == null) throw new ArgumentNullException();
Contract.EndContractBlock();
bool ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, out ignoreCase, out listType);
RuntimeEventInfo[] cache = Cache.GetEventList(listType, name);
EventInfo match = null;
bindingAttr ^= BindingFlags.DeclaredOnly;
for (int i = 0; i < cache.Length; i++)
{
RuntimeEventInfo eventInfo = cache[i];
if ((bindingAttr & eventInfo.BindingFlags) == eventInfo.BindingFlags)
{
if (match != null)
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
match = eventInfo;
}
}
return match;
}
public override FieldInfo GetField(String name, BindingFlags bindingAttr)
{
if (name == null) throw new ArgumentNullException();
Contract.EndContractBlock();
bool ignoreCase;
MemberListType listType;
RuntimeType.FilterHelper(bindingAttr, ref name, out ignoreCase, out listType);
RuntimeFieldInfo[] cache = Cache.GetFieldList(listType, name);
FieldInfo match = null;
bindingAttr ^= BindingFlags.DeclaredOnly;
bool multipleStaticFieldMatches = false;
for (int i = 0; i < cache.Length; i++)
{
RuntimeFieldInfo fieldInfo = cache[i];
if ((bindingAttr & fieldInfo.BindingFlags) == fieldInfo.BindingFlags)
{
if (match != null)
{
if (Object.ReferenceEquals(fieldInfo.DeclaringType, match.DeclaringType))
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
if ((match.DeclaringType.IsInterface == true) && (fieldInfo.DeclaringType.IsInterface == true))
multipleStaticFieldMatches = true;
}
if (match == null || fieldInfo.DeclaringType.IsSubclassOf(match.DeclaringType) || match.DeclaringType.IsInterface)
match = fieldInfo;
}
}
if (multipleStaticFieldMatches && match.DeclaringType.IsInterface)
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
return match;
}
public override Type GetInterface(String fullname, bool ignoreCase)
{
if (fullname == null) throw new ArgumentNullException();
Contract.EndContractBlock();
BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.NonPublic;
bindingAttr &= ~BindingFlags.Static;
if (ignoreCase)
bindingAttr |= BindingFlags.IgnoreCase;
string name, ns;
MemberListType listType;
SplitName(fullname, out name, out ns);
RuntimeType.FilterHelper(bindingAttr, ref name, out ignoreCase, out listType);
RuntimeType[] cache = Cache.GetInterfaceList(listType, name);
RuntimeType match = null;
for (int i = 0; i < cache.Length; i++)
{
RuntimeType iface = cache[i];
if (RuntimeType.FilterApplyType(iface, bindingAttr, name, false, ns))
{
if (match != null)
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
match = iface;
}
}
return match;
}
public override Type GetNestedType(String fullname, BindingFlags bindingAttr)
{
if (fullname == null) throw new ArgumentNullException();
Contract.EndContractBlock();
bool ignoreCase;
bindingAttr &= ~BindingFlags.Static;
string name, ns;
MemberListType listType;
SplitName(fullname, out name, out ns);
RuntimeType.FilterHelper(bindingAttr, ref name, out ignoreCase, out listType);
RuntimeType[] cache = Cache.GetNestedTypeList(listType, name);
RuntimeType match = null;
for (int i = 0; i < cache.Length; i++)
{
RuntimeType nestedType = cache[i];
if (RuntimeType.FilterApplyType(nestedType, bindingAttr, name, false, ns))
{
if (match != null)
throw new AmbiguousMatchException(Environment.GetResourceString("Arg_AmbiguousMatchException"));
match = nestedType;
}
}
return match;
}
public override MemberInfo[] GetMember(String name, MemberTypes type, BindingFlags bindingAttr)
{
if (name == null) throw new ArgumentNullException();
Contract.EndContractBlock();
ListBuilder<MethodInfo> methods = new ListBuilder<MethodInfo>();
ListBuilder<ConstructorInfo> constructors = new ListBuilder<ConstructorInfo>();
ListBuilder<PropertyInfo> properties = new ListBuilder<PropertyInfo>();
ListBuilder<EventInfo> events = new ListBuilder<EventInfo>();
ListBuilder<FieldInfo> fields = new ListBuilder<FieldInfo>();
ListBuilder<Type> nestedTypes = new ListBuilder<Type>();
int totalCount = 0;
// Methods
if ((type & MemberTypes.Method) != 0)
{
methods = GetMethodCandidates(name, bindingAttr, CallingConventions.Any, null, true);
if (type == MemberTypes.Method)
return methods.ToArray();
totalCount += methods.Count;
}
// Constructors
if ((type & MemberTypes.Constructor) != 0)
{
constructors = GetConstructorCandidates(name, bindingAttr, CallingConventions.Any, null, true);
if (type == MemberTypes.Constructor)
return constructors.ToArray();
totalCount += constructors.Count;
}
// Properties
if ((type & MemberTypes.Property) != 0)
{
properties = GetPropertyCandidates(name, bindingAttr, null, true);
if (type == MemberTypes.Property)
return properties.ToArray();
totalCount += properties.Count;
}
// Events
if ((type & MemberTypes.Event) != 0)
{
events = GetEventCandidates(name, bindingAttr, true);
if (type == MemberTypes.Event)
return events.ToArray();
totalCount += events.Count;
}
// Fields
if ((type & MemberTypes.Field) != 0)
{
fields = GetFieldCandidates(name, bindingAttr, true);
if (type == MemberTypes.Field)
return fields.ToArray();
totalCount += fields.Count;
}
// NestedTypes
if ((type & (MemberTypes.NestedType | MemberTypes.TypeInfo)) != 0)
{
nestedTypes = GetNestedTypeCandidates(name, bindingAttr, true);
if (type == MemberTypes.NestedType || type == MemberTypes.TypeInfo)
return nestedTypes.ToArray();
totalCount += nestedTypes.Count;
}
MemberInfo[] compressMembers = (type == (MemberTypes.Method | MemberTypes.Constructor)) ?
new MethodBase[totalCount] : new MemberInfo[totalCount];
int i = 0;
methods.CopyTo(compressMembers, i); i += methods.Count;
constructors.CopyTo(compressMembers, i); i += constructors.Count;
properties.CopyTo(compressMembers, i); i += properties.Count;
events.CopyTo(compressMembers, i); i += events.Count;
fields.CopyTo(compressMembers, i); i += fields.Count;
nestedTypes.CopyTo(compressMembers, i); i += nestedTypes.Count;
Contract.Assert(i == compressMembers.Length);
return compressMembers;
}
#endregion
#region Identity
public override Module Module
{
get
{
return GetRuntimeModule();
}
}
internal RuntimeModule GetRuntimeModule()
{
return RuntimeTypeHandle.GetModule(this);
}
public override Assembly Assembly
{
get
{
return GetRuntimeAssembly();
}
}
internal RuntimeAssembly GetRuntimeAssembly()
{
return RuntimeTypeHandle.GetAssembly(this);
}
public override RuntimeTypeHandle TypeHandle
{
get
{
return new RuntimeTypeHandle(this);
}
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal sealed override RuntimeTypeHandle GetTypeHandleInternal()
{
return new RuntimeTypeHandle(this);
}
[System.Security.SecuritySafeCritical]
internal bool IsCollectible()
{
return RuntimeTypeHandle.IsCollectible(GetTypeHandleInternal());
}
[System.Security.SecuritySafeCritical] // auto-generated
protected override TypeCode GetTypeCodeImpl()
{
TypeCode typeCode = Cache.TypeCode;
if (typeCode != TypeCode.Empty)
return typeCode;
CorElementType corElementType = RuntimeTypeHandle.GetCorElementType(this);
switch (corElementType)
{
case CorElementType.Boolean:
typeCode = TypeCode.Boolean; break;
case CorElementType.Char:
typeCode = TypeCode.Char; break;
case CorElementType.I1:
typeCode = TypeCode.SByte; break;
case CorElementType.U1:
typeCode = TypeCode.Byte; break;
case CorElementType.I2:
typeCode = TypeCode.Int16; break;
case CorElementType.U2:
typeCode = TypeCode.UInt16; break;
case CorElementType.I4:
typeCode = TypeCode.Int32; break;
case CorElementType.U4:
typeCode = TypeCode.UInt32; break;
case CorElementType.I8:
typeCode = TypeCode.Int64; break;
case CorElementType.U8:
typeCode = TypeCode.UInt64; break;
case CorElementType.R4:
typeCode = TypeCode.Single; break;
case CorElementType.R8:
typeCode = TypeCode.Double; break;
case CorElementType.String:
typeCode = TypeCode.String; break;
case CorElementType.ValueType:
if (this == Convert.ConvertTypes[(int)TypeCode.Decimal])
typeCode = TypeCode.Decimal;
else if (this == Convert.ConvertTypes[(int)TypeCode.DateTime])
typeCode = TypeCode.DateTime;
else if (this.IsEnum)
typeCode = Type.GetTypeCode(Enum.GetUnderlyingType(this));
else
typeCode = TypeCode.Object;
break;
default:
if (this == Convert.ConvertTypes[(int)TypeCode.DBNull])
typeCode = TypeCode.DBNull;
else if (this == Convert.ConvertTypes[(int)TypeCode.String])
typeCode = TypeCode.String;
else
typeCode = TypeCode.Object;
break;
}
Cache.TypeCode = typeCode;
return typeCode;
}
public override MethodBase DeclaringMethod
{
get
{
if (!IsGenericParameter)
throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
Contract.EndContractBlock();
IRuntimeMethodInfo declaringMethod = RuntimeTypeHandle.GetDeclaringMethod(this);
if (declaringMethod == null)
return null;
return GetMethodBase(RuntimeMethodHandle.GetDeclaringType(declaringMethod), declaringMethod);
}
}
#endregion
#region Hierarchy
[System.Security.SecuritySafeCritical] // auto-generated
public override bool IsInstanceOfType(Object o)
{
return RuntimeTypeHandle.IsInstanceOfType(this, o);
}
[System.Runtime.InteropServices.ComVisible(true)]
[Pure]
public override bool IsSubclassOf(Type type)
{
if ((object)type == null)
throw new ArgumentNullException("type");
Contract.EndContractBlock();
RuntimeType rtType = type as RuntimeType;
if (rtType == null)
return false;
RuntimeType baseType = GetBaseType();
while (baseType != null)
{
if (baseType == rtType)
return true;
baseType = baseType.GetBaseType();
}
// pretty much everything is a subclass of object, even interfaces
// notice that interfaces are really odd because they do not have a BaseType
// yet IsSubclassOf(typeof(object)) returns true
if (rtType == RuntimeType.ObjectType && rtType != this)
return true;
return false;
}
public override bool IsAssignableFrom(System.Reflection.TypeInfo typeInfo){
if(typeInfo==null) return false;
return IsAssignableFrom(typeInfo.AsType());
}
public override bool IsAssignableFrom(Type c)
{
if ((object)c == null)
return false;
if (Object.ReferenceEquals(c, this))
return true;
RuntimeType fromType = c.UnderlyingSystemType as RuntimeType;
// For runtime type, let the VM decide.
if (fromType != null)
{
// both this and c (or their underlying system types) are runtime types
return RuntimeTypeHandle.CanCastTo(fromType, this);
}
// Special case for TypeBuilder to be backward-compatible.
if (c is System.Reflection.Emit.TypeBuilder)
{
// If c is a subclass of this class, then c can be cast to this type.
if (c.IsSubclassOf(this))
return true;
if (this.IsInterface)
{
return c.ImplementInterface(this);
}
else if (this.IsGenericParameter)
{
Type[] constraints = GetGenericParameterConstraints();
for (int i = 0; i < constraints.Length; i++)
if (!constraints[i].IsAssignableFrom(c))
return false;
return true;
}
}
// For anything else we return false.
return false;
}
#if !FEATURE_CORECLR
// Reflexive, symmetric, transitive.
public override bool IsEquivalentTo(Type other)
{
RuntimeType otherRtType = other as RuntimeType;
if ((object)otherRtType == null)
return false;
if (otherRtType == this)
return true;
// It's not worth trying to perform further checks in managed
// as they would lead to FCalls anyway.
return RuntimeTypeHandle.IsEquivalentTo(this, otherRtType);
}
#endif // FEATURE_CORECLR
public override Type BaseType
{
get
{
return GetBaseType();
}
}
private RuntimeType GetBaseType()
{
if (IsInterface)
return null;
if (RuntimeTypeHandle.IsGenericVariable(this))
{
Type[] constraints = GetGenericParameterConstraints();
RuntimeType baseType = RuntimeType.ObjectType;
for (int i = 0; i < constraints.Length; i++)
{
RuntimeType constraint = (RuntimeType)constraints[i];
if (constraint.IsInterface)
continue;
if (constraint.IsGenericParameter)
{
GenericParameterAttributes special;
special = constraint.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
if ((special & GenericParameterAttributes.ReferenceTypeConstraint) == 0 &&
(special & GenericParameterAttributes.NotNullableValueTypeConstraint) == 0)
continue;
}
baseType = constraint;
}
if (baseType == RuntimeType.ObjectType)
{
GenericParameterAttributes special;
special = GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
if ((special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
baseType = RuntimeType.ValueType;
}
return baseType;
}
return RuntimeTypeHandle.GetBaseType(this);
}
public override Type UnderlyingSystemType
{
get
{
return this;
}
}
#endregion
#region Name
public override String FullName
{
get
{
return GetCachedName(TypeNameKind.FullName);
}
}
public override String AssemblyQualifiedName
{
get
{
string fullname = FullName;
// FullName is null if this type contains generic parameters but is not a generic type definition.
if (fullname == null)
return null;
return Assembly.CreateQualifiedName(this.Assembly.FullName, fullname);
}
}
public override String Namespace
{
get
{
string ns = Cache.GetNameSpace();
if (ns == null || ns.Length == 0)
return null;
return ns;
}
}
#endregion
#region Attributes
[System.Security.SecuritySafeCritical] // auto-generated
protected override TypeAttributes GetAttributeFlagsImpl()
{
return RuntimeTypeHandle.GetAttributes(this);
}
public override Guid GUID
{
[System.Security.SecuritySafeCritical] // auto-generated
get
{
Guid result = new Guid ();
GetGUID(ref result);
return result;
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern void GetGUID(ref Guid result);
[System.Security.SecuritySafeCritical] // auto-generated
protected override bool IsContextfulImpl()
{
return RuntimeTypeHandle.IsContextful(this);
}
/*
protected override bool IsMarshalByRefImpl()
{
return GetTypeHandleInternal().IsMarshalByRef();
}
*/
protected override bool IsByRefImpl()
{
return RuntimeTypeHandle.IsByRef(this);
}
protected override bool IsPrimitiveImpl()
{
return RuntimeTypeHandle.IsPrimitive(this);
}
protected override bool IsPointerImpl()
{
return RuntimeTypeHandle.IsPointer(this);
}
[System.Security.SecuritySafeCritical] // auto-generated
protected override bool IsCOMObjectImpl()
{
return RuntimeTypeHandle.IsComObject(this, false);
}
[System.Security.SecuritySafeCritical] // auto-generated
private bool IsZappedImpl()
{
return RuntimeTypeHandle.IsZapped(this);
}
[System.Security.SecuritySafeCritical] // auto-generated
private bool IsDoNotForceOrderOfConstructorsSetImpl()
{
return RuntimeTypeHandle.IsDoNotForceOrderOfConstructorsSet();
}
#if FEATURE_COMINTEROP
[SecuritySafeCritical]
internal override bool IsWindowsRuntimeObjectImpl()
{
return IsWindowsRuntimeObjectType(this);
}
[SecuritySafeCritical]
internal override bool IsExportedToWindowsRuntimeImpl()
{
return IsTypeExportedToWindowsRuntime(this);
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[SecurityCritical]
private static extern bool IsWindowsRuntimeObjectType(RuntimeType type);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[SecurityCritical]
private static extern bool IsTypeExportedToWindowsRuntime(RuntimeType type);
#endif // FEATURE_COMINTEROP
[System.Security.SecuritySafeCritical] // auto-generated
internal override bool HasProxyAttributeImpl()
{
return RuntimeTypeHandle.HasProxyAttribute(this);
}
internal bool IsDelegate()
{
return GetBaseType() == typeof(System.MulticastDelegate);
}
protected override bool IsValueTypeImpl()
{
// We need to return true for generic parameters with the ValueType constraint.
// So we cannot use the faster RuntimeTypeHandle.IsValueType because it returns
// false for all generic parameters.
if (this == typeof(ValueType) || this == typeof(Enum))
return false;
return IsSubclassOf(typeof(ValueType));
}
#if !FEATURE_CORECLR
public override bool IsEnum
{
get
{
return GetBaseType() == RuntimeType.EnumType;
}
}
#endif
protected override bool HasElementTypeImpl()
{
return RuntimeTypeHandle.HasElementType(this);
}
public override GenericParameterAttributes GenericParameterAttributes
{
[System.Security.SecuritySafeCritical] // auto-generated
get
{
if (!IsGenericParameter)
throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
Contract.EndContractBlock();
GenericParameterAttributes attributes;
RuntimeTypeHandle.GetMetadataImport(this).GetGenericParamProps(MetadataToken, out attributes);
return attributes;
}
}
public override bool IsSecurityCritical
{
get { return new RuntimeTypeHandle(this).IsSecurityCritical(); }
}
public override bool IsSecuritySafeCritical
{
get { return new RuntimeTypeHandle(this).IsSecuritySafeCritical(); }
}
public override bool IsSecurityTransparent
{
get { return new RuntimeTypeHandle(this).IsSecurityTransparent(); }
}
#endregion
#region Arrays
internal override bool IsSzArray
{
get
{
return RuntimeTypeHandle.IsSzArray(this);
}
}
protected override bool IsArrayImpl()
{
return RuntimeTypeHandle.IsArray(this);
}
[System.Security.SecuritySafeCritical] // auto-generated
public override int GetArrayRank()
{
if (!IsArrayImpl())
throw new ArgumentException(Environment.GetResourceString("Argument_HasToBeArrayClass"));
return RuntimeTypeHandle.GetArrayRank(this);
}
public override Type GetElementType()
{
return RuntimeTypeHandle.GetElementType(this);
}
#endregion
#region Enums
public override string[] GetEnumNames()
{
if (!IsEnum)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
Contract.EndContractBlock();
String[] ret = Enum.InternalGetNames(this);
// Make a copy since we can't hand out the same array since users can modify them
String[] retVal = new String[ret.Length];
Array.Copy(ret, retVal, ret.Length);
return retVal;
}
[SecuritySafeCritical]
public override Array GetEnumValues()
{
if (!IsEnum)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
Contract.EndContractBlock();
// Get all of the values
ulong[] values = Enum.InternalGetValues(this);
// Create a generic Array
Array ret = Array.UnsafeCreateInstance(this, values.Length);
for (int i = 0; i < values.Length; i++)
{
Object val = Enum.ToObject(this, values[i]);
ret.SetValue(val, i);
}
return ret;
}
public override Type GetEnumUnderlyingType()
{
if (!IsEnum)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
Contract.EndContractBlock();
return Enum.InternalGetUnderlyingType(this);
}
public override bool IsEnumDefined(object value)
{
if (value == null)
throw new ArgumentNullException("value");
Contract.EndContractBlock();
// Check if both of them are of the same type
RuntimeType valueType = (RuntimeType)value.GetType();
// If the value is an Enum then we need to extract the underlying value from it
if (valueType.IsEnum)
{
if (!valueType.IsEquivalentTo(this))
throw new ArgumentException(Environment.GetResourceString("Arg_EnumAndObjectMustBeSameType", valueType.ToString(), this.ToString()));
valueType = (RuntimeType)valueType.GetEnumUnderlyingType();
}
// If a string is passed in
if (valueType == RuntimeType.StringType)
{
// Get all of the Fields, calling GetHashEntry directly to avoid copying
string[] names = Enum.InternalGetNames(this);
if (Array.IndexOf(names, value) >= 0)
return true;
else
return false;
}
// If an enum or integer value is passed in
if (Type.IsIntegerType(valueType))
{
RuntimeType underlyingType = Enum.InternalGetUnderlyingType(this);
if (underlyingType != valueType)
throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), underlyingType.ToString()));
ulong[] ulValues = Enum.InternalGetValues(this);
ulong ulValue = Enum.ToUInt64(value);
return (Array.BinarySearch(ulValues, ulValue) >= 0);
}
else if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
{
// if at this point the value type is not an integer type, then its type doesn't match the enum type
// NetCF used to throw an argument exception in this case
throw new ArgumentException(Environment.GetResourceString("Arg_EnumUnderlyingTypeAndObjectMustBeSameType", valueType.ToString(), GetEnumUnderlyingType()));
}
else
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_UnknownEnumType"));
}
}
public override string GetEnumName(object value)
{
if (value == null)
throw new ArgumentNullException("value");
Contract.EndContractBlock();
Type valueType = value.GetType();
if (!(valueType.IsEnum || IsIntegerType(valueType)))
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
ulong[] ulValues = Enum.InternalGetValues(this);
ulong ulValue = Enum.ToUInt64(value);
int index = Array.BinarySearch(ulValues, ulValue);
if (index >= 0)
{
string[] names = Enum.InternalGetNames(this);
return names[index];
}
return null;
}
#endregion
#region Generics
internal RuntimeType[] GetGenericArgumentsInternal()
{
return GetRootElementType().GetTypeHandleInternal().GetInstantiationInternal();
}
public override Type[] GetGenericArguments()
{
Type[] types = GetRootElementType().GetTypeHandleInternal().GetInstantiationPublic();
if (types == null)
types = EmptyArray<Type>.Value;
return types;
}
[System.Security.SecuritySafeCritical] // auto-generated
public override Type MakeGenericType(Type[] instantiation)
{
if (instantiation == null)
throw new ArgumentNullException("instantiation");
Contract.EndContractBlock();
RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length];
if (!IsGenericTypeDefinition)
throw new InvalidOperationException(
Environment.GetResourceString("Arg_NotGenericTypeDefinition", this));
if (GetGenericArguments().Length != instantiation.Length)
throw new ArgumentException(Environment.GetResourceString("Argument_GenericArgsCount"), "instantiation");
for (int i = 0; i < instantiation.Length; i ++)
{
Type instantiationElem = instantiation[i];
if (instantiationElem == null)
throw new ArgumentNullException();
RuntimeType rtInstantiationElem = instantiationElem as RuntimeType;
if (rtInstantiationElem == null)
{
Type[] instantiationCopy = new Type[instantiation.Length];
for (int iCopy = 0; iCopy < instantiation.Length; iCopy++)
instantiationCopy[iCopy] = instantiation[iCopy];
instantiation = instantiationCopy;
return System.Reflection.Emit.TypeBuilderInstantiation.MakeGenericType(this, instantiation);
}
instantiationRuntimeType[i] = rtInstantiationElem;
}
RuntimeType[] genericParameters = GetGenericArgumentsInternal();
SanityCheckGenericArguments(instantiationRuntimeType, genericParameters);
Type ret = null;
try
{
ret = new RuntimeTypeHandle(this).Instantiate(instantiationRuntimeType);
}
catch (TypeLoadException e)
{
ValidateGenericArguments(this, instantiationRuntimeType, e);
throw e;
}
return ret;
}
public override bool IsGenericTypeDefinition
{
get { return RuntimeTypeHandle.IsGenericTypeDefinition(this); }
}
public override bool IsGenericParameter
{
get { return RuntimeTypeHandle.IsGenericVariable(this); }
}
public override int GenericParameterPosition
{
get
{
if (!IsGenericParameter)
throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
Contract.EndContractBlock();
return new RuntimeTypeHandle(this).GetGenericVariableIndex();
}
}
public override Type GetGenericTypeDefinition()
{
if (!IsGenericType)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotGenericType"));
Contract.EndContractBlock();
return RuntimeTypeHandle.GetGenericTypeDefinition(this);
}
public override bool IsGenericType
{
get { return RuntimeTypeHandle.HasInstantiation(this); }
}
public override bool IsConstructedGenericType
{
get { return IsGenericType && !IsGenericTypeDefinition; }
}
public override bool ContainsGenericParameters
{
get { return GetRootElementType().GetTypeHandleInternal().ContainsGenericVariables(); }
}
public override Type[] GetGenericParameterConstraints()
{
if (!IsGenericParameter)
throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
Contract.EndContractBlock();
Type[] constraints = new RuntimeTypeHandle(this).GetConstraints();
if (constraints == null)
constraints = EmptyArray<Type>.Value;
return constraints;
}
#endregion
#region Misc
[System.Security.SecuritySafeCritical] // auto-generated
public override Type MakePointerType() { return new RuntimeTypeHandle(this).MakePointer(); }
public override Type MakeByRefType() { return new RuntimeTypeHandle(this).MakeByRef(); }
public override Type MakeArrayType() { return new RuntimeTypeHandle(this).MakeSZArray(); }
public override Type MakeArrayType(int rank)
{
if (rank <= 0)
throw new IndexOutOfRangeException();
Contract.EndContractBlock();
return new RuntimeTypeHandle(this).MakeArray(rank);
}
public override StructLayoutAttribute StructLayoutAttribute
{
[System.Security.SecuritySafeCritical] // overrides transparent public member
get
{
return (StructLayoutAttribute)StructLayoutAttribute.GetCustomAttribute(this);
}
}
#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 BinderSetInvokeProperty = BindingFlags.InvokeMethod | BindingFlags.SetProperty;
private const BindingFlags BinderGetSetField = BindingFlags.GetField | BindingFlags.SetField;
private const BindingFlags BinderSetInvokeField = BindingFlags.SetField | BindingFlags.InvokeMethod;
private const BindingFlags BinderNonFieldGetSet = (BindingFlags)0x00FFF300;
private const BindingFlags ClassicBindingMask =
BindingFlags.InvokeMethod | BindingFlags.GetProperty | BindingFlags.SetProperty |
BindingFlags.PutDispProperty | BindingFlags.PutRefDispProperty;
private static RuntimeType s_typedRef = (RuntimeType)typeof(TypedReference);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
static private extern bool CanValueSpecialCast(RuntimeType valueType, RuntimeType targetType);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
static private extern Object AllocateValueType(RuntimeType type, object value, bool fForceTypeChange);
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe Object CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
{
// this method is used by invocation in reflection to check whether a value can be assigned to type.
if (IsInstanceOfType(value))
{
// Since this cannot be a generic parameter, we use RuntimeTypeHandle.IsValueType here
// because it is faster than RuntimeType.IsValueType
Contract.Assert(!IsGenericParameter);
Type type = null;
#if FEATURE_REMOTING
// For the remoting objects Object.GetType goes through proxy. Avoid the proxy call and just get
// the type directly. It is necessary to support proxies that do not handle GetType.
RealProxy realProxy = System.Runtime.Remoting.RemotingServices.GetRealProxy(value);
if (realProxy != null)
{
type = realProxy.GetProxiedType();
}
else
{
type = value.GetType();
}
#else
type = value.GetType();
#endif
if (!Object.ReferenceEquals(type, this) && RuntimeTypeHandle.IsValueType(this))
{
// must be an equivalent type, re-box to the target type
return AllocateValueType(this, value, true);
}
else
{
return value;
}
}
// if this is a ByRef get the element type and check if it's compatible
bool isByRef = IsByRef;
if (isByRef)
{
RuntimeType elementType = RuntimeTypeHandle.GetElementType(this);
if (elementType.IsInstanceOfType(value) || value == null)
{
// need to create an instance of the ByRef if null was provided, but only if primitive, enum or value type
return AllocateValueType(elementType, value, false);
}
}
else if (value == null)
return value;
else if (this == s_typedRef)
// everything works for a typedref
return value;
// check the strange ones courtesy of reflection:
// - implicit cast between primitives
// - enum treated as underlying type
// - IntPtr and System.Reflection.Pointer to pointer types
bool needsSpecialCast = IsPointer || IsEnum || IsPrimitive;
if (needsSpecialCast)
{
RuntimeType valueType;
Pointer pointer = value as Pointer;
if (pointer != null)
valueType = pointer.GetPointerType();
else
valueType = (RuntimeType)value.GetType();
if (CanValueSpecialCast(valueType, this))
{
if (pointer != null)
return pointer.GetPointerValue();
else
return value;
}
}
if ((invokeAttr & BindingFlags.ExactBinding) == BindingFlags.ExactBinding)
throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
return TryChangeType(value, binder, culture, needsSpecialCast);
}
// Factored out of CheckValue to reduce code complexity.
[System.Security.SecurityCritical]
private Object TryChangeType(Object value, Binder binder, CultureInfo culture, bool needsSpecialCast)
{
if (binder != null && binder != Type.DefaultBinder)
{
value = binder.ChangeType(value, this, culture);
if (IsInstanceOfType(value))
return value;
// if this is a ByRef get the element type and check if it's compatible
if (IsByRef)
{
RuntimeType elementType = RuntimeTypeHandle.GetElementType(this);
if (elementType.IsInstanceOfType(value) || value == null)
return AllocateValueType(elementType, value, false);
}
else if (value == null)
return value;
if (needsSpecialCast)
{
RuntimeType valueType;
Pointer pointer = value as Pointer;
if (pointer != null)
valueType = pointer.GetPointerType();
else
valueType = (RuntimeType)value.GetType();
if (CanValueSpecialCast(valueType, this))
{
if (pointer != null)
return pointer.GetPointerValue();
else
return value;
}
}
}
throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
}
// GetDefaultMembers
// This will return a MemberInfo that has been marked with the [DefaultMemberAttribute]
public override MemberInfo[] GetDefaultMembers()
{
// See if we have cached the default member name
MemberInfo[] members = null;
String defaultMemberName = GetDefaultMemberName();
if (defaultMemberName != null)
{
members = GetMember(defaultMemberName);
}
if (members == null)
members = EmptyArray<MemberInfo>.Value;
return members;
}
#if FEATURE_COMINTEROP
[System.Security.SecuritySafeCritical] // auto-generated
#endif
[DebuggerStepThroughAttribute]
[Diagnostics.DebuggerHidden]
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(Environment.GetResourceString("Arg_GenericParameter"));
Contract.EndContractBlock();
#region Preconditions
if ((bindingFlags & InvocationMask) == 0)
// "Must specify binding flags describing the invoke operation required."
throw new ArgumentException(Environment.GetResourceString("Arg_NoAccessSpec"),"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(Environment.GetResourceString("Arg_NamedParamTooBig"), "namedParams");
}
else
{
if (namedParams.Length != 0)
// "Named parameter array can not be bigger than argument array."
throw new ArgumentException(Environment.GetResourceString("Arg_NamedParamTooBig"), "namedParams");
}
}
#endregion
#region COM Interop
#if FEATURE_COMINTEROP && FEATURE_USE_LCID
if (target != null && target.GetType().IsCOMObject)
{
#region Preconditions
if ((bindingFlags & ClassicBindingMask) == 0)
throw new ArgumentException(Environment.GetResourceString("Arg_COMAccess"), "bindingFlags");
if ((bindingFlags & BindingFlags.GetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_PropSetGet"), "bindingFlags");
if ((bindingFlags & BindingFlags.InvokeMethod) != 0 && (bindingFlags & ClassicBindingMask & ~(BindingFlags.GetProperty | BindingFlags.InvokeMethod)) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_PropSetInvoke"), "bindingFlags");
if ((bindingFlags & BindingFlags.SetProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.SetProperty) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_COMPropSetPut"), "bindingFlags");
if ((bindingFlags & BindingFlags.PutDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutDispProperty) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_COMPropSetPut"), "bindingFlags");
if ((bindingFlags & BindingFlags.PutRefDispProperty) != 0 && (bindingFlags & ClassicBindingMask & ~BindingFlags.PutRefDispProperty) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_COMPropSetPut"), "bindingFlags");
#endregion
#if FEATURE_REMOTING
if(!RemotingServices.IsTransparentProxy(target))
#endif
{
#region Non-TransparentProxy case
if (name == null)
throw new ArgumentNullException("name");
bool[] isByRef = modifiers == null ? null : 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);
return InvokeDispMethod(name, bindingFlags, target, providedArgs, isByRef, lcid, namedParams);
#endregion
}
#if FEATURE_REMOTING
else
{
#region TransparentProxy case
return ((MarshalByRefObject)target).InvokeMember(name, bindingFlags, binder, providedArgs, modifiers, culture, namedParams);
#endregion
}
#endif // FEATURE_REMOTING
}
#endif // FEATURE_COMINTEROP && FEATURE_USE_LCID
#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(Environment.GetResourceString("Arg_NamedParamNull"),"namedParams");
#endregion
int argCnt = (providedArgs != null) ? providedArgs.Length : 0;
#region Get a Binder
if (binder == null)
binder = DefaultBinder;
bool bDefaultBinder = (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(Environment.GetResourceString("Arg_CreatInstAccess"),"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("name");
if (name.Length == 0 || name.Equals(@"[DISPID=0]"))
{
name = GetDefaultMemberName();
if (name == null)
{
// in InvokeMember we always pretend there is a default member if none is provided and we make it ToString
name = "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(Environment.GetResourceString("Arg_FldSetGet"),"bindingFlags");
if ((bindingFlags & BindingFlags.SetProperty) != 0)
// "Can not specify both GetField and SetProperty."
throw new ArgumentException(Environment.GetResourceString("Arg_FldGetPropSet"),"bindingFlags");
}
else
{
Contract.Assert(IsSetField);
if (providedArgs == null)
throw new ArgumentNullException("providedArgs");
if ((bindingFlags & BindingFlags.GetProperty) != 0)
// "Can not specify both SetField and GetProperty."
throw new ArgumentException(Environment.GetResourceString("Arg_FldSetPropGet"),"bindingFlags");
if ((bindingFlags & BindingFlags.InvokeMethod) != 0)
// "Can not specify Set on a Field and Invoke on a method."
throw new ArgumentException(Environment.GetResourceString("Arg_FldSetInvoke"),"bindingFlags");
}
#endregion
#region Lookup Field
FieldInfo selFld = null;
FieldInfo[] flds = GetMember(name, MemberTypes.Field, bindingFlags) as FieldInfo[];
Contract.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 || Object.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(Environment.GetResourceString("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(Environment.GetResourceString("Arg_FldGetArgErr"),"bindingFlags");
return selFld.GetValue(target);
#endregion
}
else
{
#region Set the field Value
if (argCnt != 1)
throw new ArgumentException(Environment.GetResourceString("Arg_FldSetArgErr"),"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)
{
Contract.Assert(!IsSetField);
if (isSetProperty)
throw new ArgumentException(Environment.GetResourceString("Arg_PropSetGet"), "bindingFlags");
}
else
{
Contract.Assert(isSetProperty);
Contract.Assert(!IsGetField);
if ((bindingFlags & BindingFlags.InvokeMethod) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_PropSetInvoke"), "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<MethodInfo> results = null;
for(int i = 0; i < semiFinalists.Length; i ++)
{
MethodInfo semiFinalist = semiFinalists[i];
Contract.Assert(semiFinalist != null);
if (!FilterApplyMethodInfo((RuntimeMethodInfo)semiFinalist, bindingFlags, CallingConventions.Any, new Type[argCnt]))
continue;
if (finalist == null)
{
finalist = semiFinalist;
}
else
{
if (results == null)
{
results = new List<MethodInfo>(semiFinalists.Length);
results.Add(finalist);
}
results.Add(semiFinalist);
}
}
if (results != null)
{
Contract.Assert(results.Count > 1);
finalists = new MethodInfo[results.Count];
results.CopyTo(finalists);
}
#endregion
}
#endregion
Contract.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<MethodInfo> 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
{
if (results == null)
{
results = new List<MethodInfo>(semiFinalists.Length);
results.Add(finalist);
}
results.Add(semiFinalist);
}
}
if (results != null)
{
Contract.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);
}
if (finalists == null)
finalists = new MethodInfo[] { finalist };
if (providedArgs == null)
providedArgs = EmptyArray<Object>.Value;
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
#endregion
#region Object Overrides
[Pure]
public override bool Equals(object obj)
{
// ComObjects are identified by the instance of the Type object and not the TypeHandle.
return obj == (object)this;
}
public override int GetHashCode()
{
return RuntimeHelpers.GetHashCode(this);
}
#if !FEATURE_CORECLR
public static bool operator ==(RuntimeType left, RuntimeType right)
{
return object.ReferenceEquals(left, right);
}
public static bool operator !=(RuntimeType left, RuntimeType right)
{
return !object.ReferenceEquals(left, right);
}
#endif // !FEATURE_CORECLR
public override String ToString()
{
return GetCachedName(TypeNameKind.ToString);
}
#endregion
#region ICloneable
public Object Clone()
{
return this;
}
#endregion
#region ISerializable
[System.Security.SecurityCritical] // auto-generated
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info==null)
throw new ArgumentNullException("info");
Contract.EndContractBlock();
UnitySerializationHolder.GetUnitySerializationInfo(info, this);
}
#endregion
#region ICustomAttributeProvider
[System.Security.SecuritySafeCritical] // auto-generated
public override Object[] GetCustomAttributes(bool inherit)
{
return CustomAttribute.GetCustomAttributes(this, RuntimeType.ObjectType, inherit);
}
[System.Security.SecuritySafeCritical] // auto-generated
public override Object[] GetCustomAttributes(Type attributeType, bool inherit)
{
if ((object)attributeType == null)
throw new ArgumentNullException("attributeType");
Contract.EndContractBlock();
RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
if (attributeRuntimeType == null)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"),"attributeType");
return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType, inherit);
}
[System.Security.SecuritySafeCritical] // auto-generated
public override bool IsDefined(Type attributeType, bool inherit)
{
if ((object)attributeType == null)
throw new ArgumentNullException("attributeType");
Contract.EndContractBlock();
RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
if (attributeRuntimeType == null)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"),"attributeType");
return CustomAttribute.IsDefined(this, attributeRuntimeType, inherit);
}
public override IList<CustomAttributeData> GetCustomAttributesData()
{
return CustomAttributeData.GetCustomAttributesInternal(this);
}
#endregion
#region MemberInfo Overrides
public override String Name
{
get
{
return GetCachedName(TypeNameKind.Name);
}
}
// This is used by the ToString() overrides of all reflection types. The legacy behavior has the following problems:
// 1. Use only Name for nested types, which can be confused with global types and generic parameters of the same name.
// 2. Use only Name for generic parameters, which can be confused with nested types and global types of the same name.
// 3. Remove the namespace ("System") for all primitive types, which is not language neutral.
// 4. MethodBase.ToString() use "ByRef" for byref parameters which is different than Type.ToString().
// 5. ConstructorInfo.ToString() outputs "Void" as the return type. Why Void?
// Since it could be a breaking changes to fix these legacy behaviors, we only use the better and more unambiguous format
// in serialization (MemberInfoSerializationHolder).
internal override string FormatTypeName(bool serialization)
{
if (serialization)
{
return GetCachedName(TypeNameKind.SerializationName);
}
else
{
Type elementType = GetRootElementType();
// Legacy: this doesn't make sense, why use only Name for nested types but otherwise
// ToString() which contains namespace.
if (elementType.IsNested)
return Name;
string typeName = ToString();
// Legacy: why removing "System"? Is it just because C# has keywords for these types?
// If so why don't we change it to lower case to match the C# keyword casing?
if (elementType.IsPrimitive ||
elementType == typeof(void) ||
elementType == typeof(TypedReference))
{
typeName = typeName.Substring(@"System.".Length);
}
return typeName;
}
}
private string GetCachedName(TypeNameKind kind)
{
return Cache.GetName(kind);
}
public override MemberTypes MemberType
{
get
{
if (this.IsPublic || this.IsNotPublic)
return MemberTypes.TypeInfo;
else
return MemberTypes.NestedType;
}
}
public override Type DeclaringType
{
get
{
return Cache.GetEnclosingType();
}
}
public override Type ReflectedType
{
get
{
return DeclaringType;
}
}
public override int MetadataToken
{
[System.Security.SecuritySafeCritical] // auto-generated
get
{
return RuntimeTypeHandle.GetToken(this);
}
}
#endregion
#region Legacy Internal
private void CreateInstanceCheckThis()
{
if (this is ReflectionOnlyType)
throw new ArgumentException(Environment.GetResourceString("Arg_ReflectionOnlyInvoke"));
if (ContainsGenericParameters)
throw new ArgumentException(
Environment.GetResourceString("Acc_CreateGenericEx", this));
Contract.EndContractBlock();
Type elementType = this.GetRootElementType();
if (Object.ReferenceEquals(elementType, typeof(ArgIterator)))
throw new NotSupportedException(Environment.GetResourceString("Acc_CreateArgIterator"));
if (Object.ReferenceEquals(elementType, typeof(void)))
throw new NotSupportedException(Environment.GetResourceString("Acc_CreateVoid"));
}
[System.Security.SecurityCritical] // auto-generated
internal Object CreateInstanceImpl(
BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, ref StackCrawlMark stackMark)
{
CreateInstanceCheckThis();
Object server = null;
try
{
try
{
// Store the activation attributes in thread local storage.
// These attributes are later picked up by specialized
// activation services like remote activation services to
// influence the activation.
#if FEATURE_REMOTING
if(null != activationAttributes)
{
ActivationServices.PushActivationAttributes(this, activationAttributes);
}
#endif
if (args == null)
args = EmptyArray<Object>.Value;
int argCnt = args.Length;
// Without a binder we need to do use the default binder...
if (binder == null)
binder = DefaultBinder;
// deal with the __COMObject case first. It is very special because from a reflection point of view it has no ctors
// so a call to GetMemberCons would fail
if (argCnt == 0 && (bindingAttr & BindingFlags.Public) != 0 && (bindingAttr & BindingFlags.Instance) != 0
&& (IsGenericCOMObjectImpl() || IsValueType))
{
server = CreateInstanceDefaultCtor((bindingAttr & BindingFlags.NonPublic) == 0 , false, true, ref stackMark);
}
else
{
ConstructorInfo[] candidates = GetConstructors(bindingAttr);
List<MethodBase> matches = new List<MethodBase>(candidates.Length);
// We cannot use Type.GetTypeArray here because some of the args might be null
Type[] argsType = new Type[argCnt];
for (int i = 0; i < argCnt; i++)
{
if (args[i] != null)
{
argsType[i] = args[i].GetType();
}
}
for(int i = 0; i < candidates.Length; i ++)
{
if (FilterApplyConstructorInfo((RuntimeConstructorInfo)candidates[i], bindingAttr, CallingConventions.Any, argsType))
matches.Add(candidates[i]);
}
MethodBase[] cons = new MethodBase[matches.Count];
matches.CopyTo(cons);
if (cons != null && cons.Length == 0)
cons = null;
if (cons == null)
{
// Null out activation attributes before throwing exception
#if FEATURE_REMOTING
if(null != activationAttributes)
{
ActivationServices.PopActivationAttributes(this);
activationAttributes = null;
}
#endif
throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", FullName));
}
MethodBase invokeMethod;
Object state = null;
try
{
invokeMethod = binder.BindToMethod(bindingAttr, cons, ref args, null, culture, null, out state);
}
catch (MissingMethodException) { invokeMethod = null; }
if (invokeMethod == null)
{
#if FEATURE_REMOTING
// Null out activation attributes before throwing exception
if(null != activationAttributes)
{
ActivationServices.PopActivationAttributes(this);
activationAttributes = null;
}
#endif
throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", FullName));
}
// If we're creating a delegate, we're about to call a
// constructor taking an integer to represent a target
// method. Since this is very difficult (and expensive)
// to verify, we're just going to demand UnmanagedCode
// permission before allowing this. Partially trusted
// clients can instead use Delegate.CreateDelegate,
// which allows specification of the target method via
// name or MethodInfo.
//if (isDelegate)
if (RuntimeType.DelegateType.IsAssignableFrom(invokeMethod.DeclaringType))
{
#if FEATURE_CORECLR
// In CoreCLR, CAS is not exposed externally. So what we really are looking
// for is to see if the external caller of this API is transparent or not.
// We get that information from the fact that a Demand will succeed only if
// the external caller is not transparent.
try
{
#pragma warning disable 618
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
#pragma warning restore 618
}
catch
{
throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_DelegateCreationFromPT")));
}
#else // FEATURE_CORECLR
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
#endif // FEATURE_CORECLR
}
if (invokeMethod.GetParametersNoCopy().Length == 0)
{
if (args.Length != 0)
{
Contract.Assert((invokeMethod.CallingConvention & CallingConventions.VarArgs) ==
CallingConventions.VarArgs);
throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture,
Environment.GetResourceString("NotSupported_CallToVarArg")));
}
// fast path??
server = Activator.CreateInstance(this, true);
}
else
{
server = ((ConstructorInfo)invokeMethod).Invoke(bindingAttr, binder, args, culture);
if (state != null)
binder.ReorderArgumentArray(ref args, state);
}
}
}
finally
{
#if FEATURE_REMOTING
// Reset the TLS to null
if(null != activationAttributes)
{
ActivationServices.PopActivationAttributes(this);
activationAttributes = null;
}
#endif
}
}
catch (Exception)
{
throw;
}
//Console.WriteLine(server);
return server;
}
// the cache entry
class ActivatorCacheEntry
{
// the type to cache
internal readonly RuntimeType m_type;
// the delegate containing the call to the ctor, will be replaced by an IntPtr to feed a calli with
internal volatile CtorDelegate m_ctor;
internal readonly RuntimeMethodHandleInternal m_hCtorMethodHandle;
internal readonly MethodAttributes m_ctorAttributes;
// Is a security check needed before this constructor is invoked?
internal readonly bool m_bNeedSecurityCheck;
// Lazy initialization was performed
internal volatile bool m_bFullyInitialized;
[System.Security.SecurityCritical]
internal ActivatorCacheEntry(RuntimeType t, RuntimeMethodHandleInternal rmh, bool bNeedSecurityCheck)
{
m_type = t;
m_bNeedSecurityCheck = bNeedSecurityCheck;
m_hCtorMethodHandle = rmh;
if (!m_hCtorMethodHandle.IsNullHandle())
m_ctorAttributes = RuntimeMethodHandle.GetAttributes(m_hCtorMethodHandle);
}
}
//ActivatorCache
class ActivatorCache
{
const int CACHE_SIZE = 16;
volatile int hash_counter; //Counter for wrap around
readonly ActivatorCacheEntry[] cache = new ActivatorCacheEntry[CACHE_SIZE];
volatile ConstructorInfo delegateCtorInfo;
volatile PermissionSet delegateCreatePermissions;
private void InitializeDelegateCreator() {
// No synchronization needed here. In the worst case we create extra garbage
PermissionSet ps = new PermissionSet(PermissionState.None);
ps.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess));
#pragma warning disable 618
ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
#pragma warning restore 618
delegateCreatePermissions = ps;
ConstructorInfo ctorInfo = typeof(CtorDelegate).GetConstructor(new Type[] {typeof(Object), typeof(IntPtr)});
delegateCtorInfo = ctorInfo; // this assignment should be last
}
[System.Security.SecuritySafeCritical] // auto-generated
private void InitializeCacheEntry(ActivatorCacheEntry ace)
{
if (!ace.m_type.IsValueType)
{
Contract.Assert(!ace.m_hCtorMethodHandle.IsNullHandle(), "Expected the default ctor method handle for a reference type.");
if (delegateCtorInfo == null)
InitializeDelegateCreator();
delegateCreatePermissions.Assert();
// No synchronization needed here. In the worst case we create extra garbage
CtorDelegate ctor = (CtorDelegate)delegateCtorInfo.Invoke(new Object[] { null, RuntimeMethodHandle.GetFunctionPointer(ace.m_hCtorMethodHandle) });
ace.m_ctor = ctor;
}
ace.m_bFullyInitialized = true;
}
internal ActivatorCacheEntry GetEntry(RuntimeType t)
{
int index = hash_counter;
for(int i = 0; i < CACHE_SIZE; i++)
{
ActivatorCacheEntry ace = Volatile.Read(ref cache[index]);
if (ace != null && ace.m_type == t) //check for type match..
{
if (!ace.m_bFullyInitialized)
InitializeCacheEntry(ace);
return ace;
}
index = (index+1)&(ActivatorCache.CACHE_SIZE-1);
}
return null;
}
internal void SetEntry(ActivatorCacheEntry ace)
{
// fill the the array backwards to hit the most recently filled entries first in GetEntry
int index = (hash_counter-1)&(ActivatorCache.CACHE_SIZE-1);
hash_counter = index;
Volatile.Write(ref cache[index], ace);
}
}
private static volatile ActivatorCache s_ActivatorCache;
// the slow path of CreateInstanceDefaultCtor
[System.Security.SecuritySafeCritical] // auto-generated
internal Object CreateInstanceSlow(bool publicOnly, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark)
{
RuntimeMethodHandleInternal runtime_ctor = default(RuntimeMethodHandleInternal);
bool bNeedSecurityCheck = true;
bool bCanBeCached = false;
bool bSecurityCheckOff = false;
if (!skipCheckThis)
CreateInstanceCheckThis();
if (!fillCache)
bSecurityCheckOff = true;
#if FEATURE_APPX
INVOCATION_FLAGS invocationFlags = InvocationFlags;
if ((invocationFlags & INVOCATION_FLAGS.INVOCATION_FLAGS_NON_W8P_FX_API) != 0)
{
RuntimeAssembly caller = RuntimeAssembly.GetExecutingAssembly(ref stackMark);
if (caller != null && !caller.IsSafeForReflection())
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_APIInvalidForCurrentContext", this.FullName));
// Allow it because the caller is framework code, but don't cache the result
// because we need to do the stack walk every time this type is instantiated.
bSecurityCheckOff = false;
bCanBeCached = false;
}
#endif
Object instance = RuntimeTypeHandle.CreateInstance(this, publicOnly, bSecurityCheckOff, ref bCanBeCached, ref runtime_ctor, ref bNeedSecurityCheck);
if (bCanBeCached && fillCache)
{
ActivatorCache activatorCache = s_ActivatorCache;
if (activatorCache == null)
{
// No synchronization needed here. In the worst case we create extra garbage
activatorCache = new ActivatorCache();
s_ActivatorCache = activatorCache;
}
// cache the ctor
ActivatorCacheEntry ace = new ActivatorCacheEntry(this, runtime_ctor, bNeedSecurityCheck);
activatorCache.SetEntry(ace);
}
return instance;
}
// Helper to invoke the default (parameterless) ctor.
// fillCache is set in the SL2/3 compat mode or when called from Marshal.PtrToStructure.
[System.Security.SecuritySafeCritical] // auto-generated
[DebuggerStepThroughAttribute]
[Diagnostics.DebuggerHidden]
internal Object CreateInstanceDefaultCtor(bool publicOnly, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark)
{
if (GetType() == typeof(ReflectionOnlyType))
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAllowedInReflectionOnly"));
ActivatorCache activatorCache = s_ActivatorCache;
if (activatorCache != null)
{
ActivatorCacheEntry ace = activatorCache.GetEntry(this);
if (ace != null)
{
if (publicOnly)
{
if (ace.m_ctor != null &&
(ace.m_ctorAttributes & MethodAttributes.MemberAccessMask) != MethodAttributes.Public)
{
throw new MissingMethodException(Environment.GetResourceString("Arg_NoDefCTor"));
}
}
// Allocate empty object
Object instance = RuntimeTypeHandle.Allocate(this);
// if m_ctor is null, this type doesn't have a default ctor
Contract.Assert(ace.m_ctor != null || this.IsValueType);
if (ace.m_ctor != null)
{
// Perform security checks if needed
if (ace.m_bNeedSecurityCheck)
RuntimeMethodHandle.PerformSecurityCheck(instance, ace.m_hCtorMethodHandle, this, (uint)INVOCATION_FLAGS.INVOCATION_FLAGS_CONSTRUCTOR_INVOKE);
// Call ctor (value types wont have any)
try
{
ace.m_ctor(instance);
}
catch (Exception e)
{
throw new TargetInvocationException(e);
}
}
return instance;
}
}
return CreateInstanceSlow(publicOnly, skipCheckThis, fillCache, ref stackMark);
}
internal void InvalidateCachedNestedType()
{
Cache.InvalidateCachedNestedType();
}
[System.Security.SecuritySafeCritical] // auto-generated
internal bool IsGenericCOMObjectImpl()
{
return RuntimeTypeHandle.IsComObject(this, true);
}
#endregion
#region Legacy Static Internal
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern Object _CreateEnum(RuntimeType enumType, long value);
[System.Security.SecuritySafeCritical] // auto-generated
internal static Object CreateEnum(RuntimeType enumType, long value)
{
return _CreateEnum(enumType, value);
}
#if FEATURE_COMINTEROP
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern Object InvokeDispMethod(
String name, BindingFlags invokeAttr, Object target, Object[] args,
bool[] byrefModifiers, int culture, String[] namedParameters);
#if FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern Type GetTypeFromProgIDImpl(String progID, String server, bool throwOnError);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern Type GetTypeFromCLSIDImpl(Guid clsid, String server, bool throwOnError);
#else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
internal static Type GetTypeFromProgIDImpl(String progID, String server, bool throwOnError)
{
throw new NotImplementedException("CoreCLR_REMOVED -- Unmanaged activation removed"); // @
}
internal static Type GetTypeFromCLSIDImpl(Guid clsid, String server, bool throwOnError)
{
throw new NotImplementedException("CoreCLR_REMOVED -- Unmanaged activation removed"); // @
}
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
#endif
#endregion
#region COM
#if FEATURE_COMINTEROP && FEATURE_REMOTING
[System.Security.SecuritySafeCritical] // auto-generated
private Object ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, int[] aWrapperTypes, ref MessageData msgData)
{
ParameterModifier[] aParamMod = null;
Object ret = null;
// Allocate a new message
Message reqMsg = new Message();
reqMsg.InitFields(msgData);
// Retrieve the required information from the message object.
MethodInfo meth = (MethodInfo)reqMsg.GetMethodBase();
Object[] aArgs = reqMsg.Args;
int cArgs = aArgs.Length;
// Retrieve information from the method we are invoking on.
ParameterInfo[] aParams = meth.GetParametersNoCopy();
// If we have arguments, then set the byref flags to true for byref arguments.
// We also wrap the arguments that require wrapping.
if (cArgs > 0)
{
ParameterModifier paramMod = new ParameterModifier(cArgs);
for (int i = 0; i < cArgs; i++)
{
if (aParams[i].ParameterType.IsByRef)
paramMod[i] = true;
}
aParamMod = new ParameterModifier[1];
aParamMod[0] = paramMod;
if (aWrapperTypes != null)
WrapArgsForInvokeCall(aArgs, aWrapperTypes);
}
// If the method has a void return type, then set the IgnoreReturn binding flag.
if (Object.ReferenceEquals(meth.ReturnType, typeof(void)))
flags |= BindingFlags.IgnoreReturn;
try
{
// Invoke the method using InvokeMember().
ret = InvokeMember(memberName, flags, null, target, aArgs, aParamMod, null, null);
}
catch (TargetInvocationException e)
{
// For target invocation exceptions, we need to unwrap the inner exception and
// re-throw it.
throw e.InnerException;
}
// Convert each byref argument that is not of the proper type to
// the parameter type using the OleAutBinder.
for (int i = 0; i < cArgs; i++)
{
if (aParamMod[0][i] && aArgs[i] != null)
{
// The parameter is byref.
Type paramType = aParams[i].ParameterType.GetElementType();
if (!Object.ReferenceEquals(paramType, aArgs[i].GetType()))
aArgs[i] = ForwardCallBinder.ChangeType(aArgs[i], paramType, null);
}
}
// If the return type is not of the proper type, then convert it
// to the proper type using the OleAutBinder.
if (ret != null)
{
Type retType = meth.ReturnType;
if (!Object.ReferenceEquals(retType, ret.GetType()))
ret = ForwardCallBinder.ChangeType(ret, retType, null);
}
// Propagate the out parameters
RealProxy.PropagateOutParameters(reqMsg, aArgs, ret);
// Return the value returned by the InvokeMember call.
return ret;
}
[SecuritySafeCritical]
private void WrapArgsForInvokeCall(Object[] aArgs, int[] aWrapperTypes)
{
int cArgs = aArgs.Length;
for (int i = 0; i < cArgs; i++)
{
if (aWrapperTypes[i] == 0)
continue;
if (((DispatchWrapperType)aWrapperTypes[i] & DispatchWrapperType.SafeArray) != 0)
{
Type wrapperType = null;
bool isString = false;
// Determine the type of wrapper to use.
switch ((DispatchWrapperType)aWrapperTypes[i] & ~DispatchWrapperType.SafeArray)
{
case DispatchWrapperType.Unknown:
wrapperType = typeof(UnknownWrapper);
break;
case DispatchWrapperType.Dispatch:
wrapperType = typeof(DispatchWrapper);
break;
case DispatchWrapperType.Error:
wrapperType = typeof(ErrorWrapper);
break;
case DispatchWrapperType.Currency:
wrapperType = typeof(CurrencyWrapper);
break;
case DispatchWrapperType.BStr:
wrapperType = typeof(BStrWrapper);
isString = true;
break;
default:
Contract.Assert(false, "[RuntimeType.WrapArgsForInvokeCall]Invalid safe array wrapper type specified.");
break;
}
// Allocate the new array of wrappers.
Array oldArray = (Array)aArgs[i];
int numElems = oldArray.Length;
Object[] newArray = (Object[])Array.UnsafeCreateInstance(wrapperType, numElems);
// Retrieve the ConstructorInfo for the wrapper type.
ConstructorInfo wrapperCons;
if(isString)
{
wrapperCons = wrapperType.GetConstructor(new Type[] {typeof(String)});
}
else
{
wrapperCons = wrapperType.GetConstructor(new Type[] {typeof(Object)});
}
// Wrap each of the elements of the array.
for (int currElem = 0; currElem < numElems; currElem++)
{
if(isString)
{
newArray[currElem] = wrapperCons.Invoke(new Object[] {(String)oldArray.GetValue(currElem)});
}
else
{
newArray[currElem] = wrapperCons.Invoke(new Object[] {oldArray.GetValue(currElem)});
}
}
// Update the argument.
aArgs[i] = newArray;
}
else
{
// Determine the wrapper to use and then wrap the argument.
switch ((DispatchWrapperType)aWrapperTypes[i])
{
case DispatchWrapperType.Unknown:
aArgs[i] = new UnknownWrapper(aArgs[i]);
break;
case DispatchWrapperType.Dispatch:
aArgs[i] = new DispatchWrapper(aArgs[i]);
break;
case DispatchWrapperType.Error:
aArgs[i] = new ErrorWrapper(aArgs[i]);
break;
case DispatchWrapperType.Currency:
aArgs[i] = new CurrencyWrapper(aArgs[i]);
break;
case DispatchWrapperType.BStr:
aArgs[i] = new BStrWrapper((String)aArgs[i]);
break;
default:
Contract.Assert(false, "[RuntimeType.WrapArgsForInvokeCall]Invalid wrapper type specified.");
break;
}
}
}
}
private OleAutBinder ForwardCallBinder
{
get
{
// Synchronization is not required.
if (s_ForwardCallBinder == null)
s_ForwardCallBinder = new OleAutBinder();
return s_ForwardCallBinder;
}
}
[Flags]
private enum DispatchWrapperType : int
{
// This enum must stay in sync with the DispatchWrapperType enum defined in MLInfo.h
Unknown = 0x00000001,
Dispatch = 0x00000002,
Record = 0x00000004,
Error = 0x00000008,
Currency = 0x00000010,
BStr = 0x00000020,
SafeArray = 0x00010000
}
private static volatile OleAutBinder s_ForwardCallBinder;
#endif // FEATURE_COMINTEROP && FEATURE_REMOTING
#endregion
}
// this is the introspection only type. This type overrides all the functions with runtime semantics
// and throws an exception.
// The idea behind this type is that it relieves RuntimeType from doing honerous checks about ReflectionOnly
// context.
// This type should not derive from RuntimeType but it's doing so for convinience.
// That should not present a security threat though it is risky as a direct call to one of the base method
// method (RuntimeType) and an instance of this type will work around the reason to have this type in the
// first place. However given RuntimeType is not public all its methods are protected and require full trust
// to be accessed
[Serializable]
internal class ReflectionOnlyType : RuntimeType {
private ReflectionOnlyType() {}
// always throw
public override RuntimeTypeHandle TypeHandle
{
get
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotAllowedInReflectionOnly"));
}
}
}
#region Library
internal unsafe struct Utf8String
{
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern unsafe bool EqualsCaseSensitive(void* szLhs, void* szRhs, int cSz);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern unsafe bool EqualsCaseInsensitive(void* szLhs, void* szRhs, int cSz);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern unsafe uint HashCaseInsensitive(void* sz, int cSz);
[System.Security.SecurityCritical] // auto-generated
private static int GetUtf8StringByteLength(void* pUtf8String)
{
int len = 0;
unsafe
{
byte* pItr = (byte*)pUtf8String;
while (*pItr != 0)
{
len++;
pItr++;
}
}
return len;
}
[SecurityCritical]
private void* m_pStringHeap; // This is the raw UTF8 string.
private int m_StringHeapByteLength;
[System.Security.SecurityCritical] // auto-generated
internal Utf8String(void* pStringHeap)
{
m_pStringHeap = pStringHeap;
if (pStringHeap != null)
{
m_StringHeapByteLength = GetUtf8StringByteLength(pStringHeap);
}
else
{
m_StringHeapByteLength = 0;
}
}
[System.Security.SecurityCritical] // auto-generated
internal unsafe Utf8String(void* pUtf8String, int cUtf8String)
{
m_pStringHeap = pUtf8String;
m_StringHeapByteLength = cUtf8String;
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe bool Equals(Utf8String s)
{
if (m_pStringHeap == null)
{
return s.m_StringHeapByteLength == 0;
}
if ((s.m_StringHeapByteLength == m_StringHeapByteLength) && (m_StringHeapByteLength != 0))
{
return Utf8String.EqualsCaseSensitive(s.m_pStringHeap, m_pStringHeap, m_StringHeapByteLength);
}
return false;
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe bool EqualsCaseInsensitive(Utf8String s)
{
if (m_pStringHeap == null)
{
return s.m_StringHeapByteLength == 0;
}
if ((s.m_StringHeapByteLength == m_StringHeapByteLength) && (m_StringHeapByteLength != 0))
{
return Utf8String.EqualsCaseInsensitive(s.m_pStringHeap, m_pStringHeap, m_StringHeapByteLength);
}
return false;
}
[System.Security.SecuritySafeCritical] // auto-generated
internal unsafe uint HashCaseInsensitive()
{
return Utf8String.HashCaseInsensitive(m_pStringHeap, m_StringHeapByteLength);
}
[System.Security.SecuritySafeCritical] // auto-generated
public override string ToString()
{
unsafe
{
byte* buf = stackalloc byte[m_StringHeapByteLength];
byte* pItr = (byte*)m_pStringHeap;
for (int currentPos = 0; currentPos < m_StringHeapByteLength; currentPos++)
{
buf[currentPos] = *pItr;
pItr++;
}
if (m_StringHeapByteLength == 0)
return "";
int cResult = Encoding.UTF8.GetCharCount(buf, m_StringHeapByteLength);
char* result = stackalloc char[cResult];
Encoding.UTF8.GetChars(buf, m_StringHeapByteLength, result, cResult);
return new string(result, 0, cResult);
}
}
}
#endregion
}
namespace System.Reflection
{
// Reliable hashtable thread safe for multiple readers and single writer. Note that the reliability goes together with thread
// safety. Thread safety for multiple readers requires atomic update of the state that also makes makes the table
// reliable in the presence of asynchronous exceptions.
internal struct CerHashtable<K, V> where K : class
{
private class Table
{
// Note that m_keys and m_values arrays are immutable to allow lock-free reads. A new instance
// of CerHashtable has to be allocated to grow the size of the hashtable.
internal K[] m_keys;
internal V[] m_values;
internal int m_count;
internal Table(int size)
{
size = HashHelpers.GetPrime(size);
m_keys = new K[size];
m_values = new V[size];
}
internal void Insert(K key, V value)
{
int hashcode = GetHashCodeHelper(key);
if (hashcode < 0)
hashcode = ~hashcode;
K[] keys = m_keys;
int index = hashcode % keys.Length;
while (true)
{
K hit = keys[index];
if (hit == null)
{
m_count++;
m_values[index] = value;
// This volatile write has to be last. It is going to publish the result atomically.
//
// Note that incrementing the count or setting the value does not do any harm without setting the key. The inconsistency will be ignored
// and it will go away completely during next rehash.
Volatile.Write(ref keys[index], key);
break;
}
else
{
Contract.Assert(!hit.Equals(key), "Key was already in CerHashtable! Potential ---- (or bug) in the Reflection cache?");
index++;
if (index >= keys.Length)
index -= keys.Length;
}
}
}
}
private Table m_Table;
private const int MinSize = 7;
private static int GetHashCodeHelper(K key)
{
string sKey = key as string;
// For strings we don't want the key to differ across domains as CerHashtable might be shared.
if(sKey == null)
{
return key.GetHashCode();
}
else
{
return sKey.GetLegacyNonRandomizedHashCode();
}
}
private void Rehash(int newSize)
{
Table newTable = new Table(newSize);
Table oldTable = m_Table;
if (oldTable != null)
{
K[] keys = oldTable.m_keys;
V[] values = oldTable.m_values;
for (int i = 0; i < keys.Length; i++)
{
K key = keys[i];
if (key != null)
{
newTable.Insert(key, values[i]);
}
}
}
// Publish the new table atomically
Volatile.Write(ref m_Table, newTable);
}
internal V this[K key]
{
set
{
Table table = m_Table;
if (table != null)
{
int requiredSize = 2 * (table.m_count + 1);
if (requiredSize >= table.m_keys.Length)
Rehash(requiredSize);
}
else
{
Rehash(MinSize);
}
m_Table.Insert(key, value);
}
get
{
Table table = Volatile.Read(ref m_Table);
if (table == null)
return default(V);
int hashcode = GetHashCodeHelper(key);
if (hashcode < 0)
hashcode = ~hashcode;
K[] keys = table.m_keys;
int index = hashcode % keys.Length;
while (true)
{
// This volatile read has to be first. It is reading the atomically published result.
K hit = Volatile.Read(ref keys[index]);
if (hit != null)
{
if (hit.Equals(key))
return table.m_values[index];
index++;
if (index >= keys.Length)
index -= keys.Length;
}
else
{
return default(V);
}
}
}
}
}
}
|