in src/dotnet-svcutil/lib/src/FrameworkFork/System.Runtime.Serialization/System/Runtime/Serialization/CollectionDataContract.cs [993:1187]
private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract dataContract, out Type itemType, bool constructorRequired)
{
dataContract = null;
itemType = Globals.TypeOfObject;
if (DataContract.GetBuiltInDataContract(type) != null)
{
return HandleIfInvalidCollection(type, tryCreate, false/*hasCollectionDataContract*/, false/*isBaseTypeCollection*/,
SRSerialization.CollectionTypeCannotBeBuiltIn, null, ref dataContract);
}
MethodInfo addMethod, getEnumeratorMethod;
bool hasCollectionDataContract = IsCollectionDataContract(type);
Type baseType = type.GetTypeInfo().BaseType;
bool isBaseTypeCollection = (baseType != null && baseType != Globals.TypeOfObject
&& baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) ? IsCollection(baseType) : false;
if (type.GetTypeInfo().IsAttributeDefined(Globals.TypeOfDataContractAttribute))
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection,
SRSerialization.CollectionTypeCannotHaveDataContract, null, ref dataContract);
}
if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) || IsArraySegment(type))
{
return false;
}
if (!Globals.TypeOfIEnumerable.IsAssignableFrom(type))
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection,
SRSerialization.CollectionTypeIsNotIEnumerable, null, ref dataContract);
}
if (type.GetTypeInfo().IsInterface)
{
Type interfaceTypeToCheck = type.GetTypeInfo().IsGenericType ? type.GetGenericTypeDefinition() : type;
Type[] knownInterfaces = KnownInterfaces;
for (int i = 0; i < knownInterfaces.Length; i++)
{
if (knownInterfaces[i] == interfaceTypeToCheck)
{
addMethod = null;
if (type.GetTypeInfo().IsGenericType)
{
Type[] genericArgs = type.GetGenericArguments();
if (interfaceTypeToCheck == Globals.TypeOfIDictionaryGeneric)
{
itemType = Globals.TypeOfKeyValue.MakeGenericType(genericArgs);
addMethod = type.GetMethod(Globals.AddMethodName);
getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(genericArgs)).GetMethod(Globals.GetEnumeratorMethodName);
}
else
{
itemType = genericArgs[0];
// ICollection<T> has AddMethod
var collectionType = Globals.TypeOfICollectionGeneric.MakeGenericType(itemType);
if (collectionType.IsAssignableFrom(type))
{
addMethod = collectionType.GetMethod(Globals.AddMethodName);
}
getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(itemType).GetMethod(Globals.GetEnumeratorMethodName);
}
}
else
{
if (interfaceTypeToCheck == Globals.TypeOfIDictionary)
{
itemType = typeof(KeyValue<object, object>);
addMethod = type.GetMethod(Globals.AddMethodName);
}
else
{
itemType = Globals.TypeOfObject;
// IList has AddMethod
if (interfaceTypeToCheck == Globals.TypeOfIList)
{
addMethod = type.GetMethod(Globals.AddMethodName);
}
}
getEnumeratorMethod = Globals.TypeOfIEnumerable.GetMethod(Globals.GetEnumeratorMethodName);
}
if (tryCreate)
dataContract = new CollectionDataContract(type, (CollectionKind)(i + 1), itemType, getEnumeratorMethod, addMethod, null/*defaultCtor*/);
return true;
}
}
}
ConstructorInfo defaultCtor = null;
if (!type.GetTypeInfo().IsValueType)
{
defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty<Type>());
if (defaultCtor == null && constructorRequired)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection/*createContractWithException*/,
SRSerialization.CollectionTypeDoesNotHaveDefaultCtor, null, ref dataContract);
}
}
Type knownInterfaceType = null;
CollectionKind kind = CollectionKind.None;
bool multipleDefinitions = false;
Type[] interfaceTypes = type.GetInterfaces();
foreach (Type interfaceType in interfaceTypes)
{
Type interfaceTypeToCheck = interfaceType.GetTypeInfo().IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;
Type[] knownInterfaces = KnownInterfaces;
for (int i = 0; i < knownInterfaces.Length; i++)
{
if (knownInterfaces[i] == interfaceTypeToCheck)
{
CollectionKind currentKind = (CollectionKind)(i + 1);
if (kind == CollectionKind.None || currentKind < kind)
{
kind = currentKind;
knownInterfaceType = interfaceType;
multipleDefinitions = false;
}
else if ((kind & currentKind) == currentKind)
multipleDefinitions = true;
break;
}
}
}
if (kind == CollectionKind.None)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection,
SRSerialization.CollectionTypeIsNotIEnumerable, null, ref dataContract);
}
if (kind == CollectionKind.Enumerable || kind == CollectionKind.Collection || kind == CollectionKind.GenericEnumerable)
{
if (multipleDefinitions)
knownInterfaceType = Globals.TypeOfIEnumerable;
itemType = knownInterfaceType.GetTypeInfo().IsGenericType ? knownInterfaceType.GetGenericArguments()[0] : Globals.TypeOfObject;
GetCollectionMethods(type, knownInterfaceType, new Type[] { itemType },
false /*addMethodOnInterface*/,
out getEnumeratorMethod, out addMethod);
if (addMethod == null)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection/*createContractWithException*/,
SRSerialization.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), ref dataContract);
}
if (tryCreate)
dataContract = new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
}
else
{
if (multipleDefinitions)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, isBaseTypeCollection/*createContractWithException*/,
SRSerialization.CollectionTypeHasMultipleDefinitionsOfInterface, KnownInterfaces[(int)kind - 1].Name, ref dataContract);
}
Type[] addMethodTypeArray = null;
switch (kind)
{
case CollectionKind.GenericDictionary:
addMethodTypeArray = knownInterfaceType.GetGenericArguments();
bool isOpenGeneric = knownInterfaceType.GetTypeInfo().IsGenericTypeDefinition
|| (addMethodTypeArray[0].IsGenericParameter && addMethodTypeArray[1].IsGenericParameter);
itemType = isOpenGeneric ? Globals.TypeOfKeyValue : Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
break;
case CollectionKind.Dictionary:
addMethodTypeArray = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
itemType = Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
break;
case CollectionKind.GenericList:
case CollectionKind.GenericCollection:
addMethodTypeArray = knownInterfaceType.GetGenericArguments();
itemType = addMethodTypeArray[0];
break;
case CollectionKind.List:
itemType = Globals.TypeOfObject;
addMethodTypeArray = new Type[] { itemType };
break;
}
if (tryCreate)
{
GetCollectionMethods(type, knownInterfaceType, addMethodTypeArray,
true /*addMethodOnInterface*/,
out getEnumeratorMethod, out addMethod);
#if !NET_NATIVE
dataContract = new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
#else
dataContract = DataContract.GetDataContractFromGeneratedAssembly(type);
#endif
}
}
return true;
}