|
private static object GetIntrinsicTypeEditor(Hashtable table, Type callingType) |
|
{ |
|
object hashEntry = null; |
|
|
|
// We take a lock on this table. Nothing in this code calls out to |
|
// other methods that lock, so it should be fairly safe to grab this |
|
// lock. Also, this allows multiple intrinsic tables to be searched |
|
// at once. |
|
// |
|
lock (table) |
|
{ |
|
Type baseType = callingType; |
|
while (baseType != null && baseType != typeof(object)) |
|
{ |
|
hashEntry = table[baseType]; |
|
|
|
// If the entry is a late-bound type, then try to |
|
// resolve it. |
|
// |
|
string typeString = hashEntry as string; |
|
if (typeString != null) |
|
{ |
|
hashEntry = Type.GetType(typeString); |
|
if (hashEntry != null) |
|
{ |
|
table[baseType] = hashEntry; |
|
} |
|
} |
|
|
|
if (hashEntry != null) |
|
{ |
|
break; |
|
} |
|
|
|
baseType = baseType.BaseType; |
|
} |
|
|
|
// Now make a scan through each value in the table, looking for interfaces. |
|
// If we find one, see if the object implements the interface. |
|
// |
|
if (hashEntry == null) |
|
{ |
|
// Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations. |
|
IDictionaryEnumerator e = table.GetEnumerator(); |
|
while (e.MoveNext()) |
|
{ |
|
DictionaryEntry de = e.Entry; |
|
Type keyType = de.Key as Type; |
|
|
|
if (keyType != null && keyType.IsInterface && keyType.IsAssignableFrom(callingType)) |
|
{ |
|
hashEntry = de.Value; |
|
string typeString = hashEntry as string; |
|
|
|
if (typeString != null) |
|
{ |
|
hashEntry = Type.GetType(typeString); |
|
if (hashEntry != null) |
|
{ |
|
table[callingType] = hashEntry; |
|
} |
|
} |
|
|
|
if (hashEntry != null) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Special case converters |
|
// |
|
if (hashEntry == null) |
|
{ |
|
if (callingType.IsGenericType && callingType.GetGenericTypeDefinition() == typeof(Nullable<>)) |
|
{ |
|
// Check if it is a nullable value |
|
hashEntry = table[s_intrinsicNullableKey]; |
|
} |
|
else if (callingType.IsInterface) |
|
{ |
|
// Finally, check to see if the component type is some unknown interface. |
|
// We have a custom converter for that. |
|
hashEntry = table[s_intrinsicReferenceKey]; |
|
} |
|
} |
|
|
|
// Interfaces do not derive from object, so we |
|
// must handle the case of no hash entry here. |
|
// |
|
if (hashEntry == null) |
|
{ |
|
hashEntry = table[typeof(object)]; |
|
} |
|
|
|
// If the entry is a type, create an instance of it and then |
|
// replace the entry. This way we only need to create once. |
|
// We can only do this if the object doesn't want a type |
|
// in its constructor. |
|
// |
|
Type type = hashEntry as Type; |
|
|
|
if (type != null) |
|
{ |
|
hashEntry = CreateInstance(type, callingType); |
|
if (type.GetConstructor(s_typeConstructor) == null) |
|
{ |
|
table[callingType] = hashEntry; |
|
} |
|
} |
|
} |
|
|
|
return hashEntry; |
|
} |
There's no test coverage for the
ReflectTypeDescriptionProvider.GetIntrinsicTypeEditormethod which does core work whenTypeDescriptor.GetEditorand related methods are called:runtime/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs
Lines 1268 to 1382 in 2b93f83
The method previously handled look ups for both type converters and editors, but #39973 split the logic into separate methods to facilitate linker friendliness of intrinsic type converters. As a result, the following block of code (specific to converter look-ups ) can probably be removed from
GetIntrinsicTypeEditor:runtime/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs
Lines 1339 to 1354 in 2b93f83
The PR (#39973) held off from removing this code due to a lack of test coverage for the method and to avoid breaking upstream scenarios, such as Win Forms code.
We should also investigate code coverage for other areas in the
ReflectTypeDescriptionProviderclass.cc @eerhardt