| File: System\Runtime\Serialization\Schema\SchemaImportHelper.cs | Web Access |
| Project: src\runtime\src\libraries\System.Runtime.Serialization.Schema\src\System.Runtime.Serialization.Schema.csproj (System.Runtime.Serialization.Schema) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization.DataContracts; using System.Xml; namespace System.Runtime.Serialization { internal enum DataContractType { ClassDataContract, CollectionDataContract, EnumDataContract, PrimitiveDataContract, XmlDataContract, Unknown = -1 } internal static class DataContractExtensions { internal static DataContractType GetContractType(this DataContract dataContract) => dataContract.ContractType switch { "ClassDataContract" => DataContractType.ClassDataContract, "CollectionDataContract" => DataContractType.CollectionDataContract, "EnumDataContract" => DataContractType.EnumDataContract, "PrimitiveDataContract" => DataContractType.PrimitiveDataContract, "XmlDataContract" => DataContractType.XmlDataContract, _ => DataContractType.Unknown }; internal static bool Is(this DataContract dataContract, DataContractType dcType) { return (dataContract.GetContractType() == dcType); } internal static DataContract? As(this DataContract dataContract, DataContractType dcType) { if (dataContract.GetContractType() == dcType) return dataContract; return null; } [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal static bool IsCollectionItemNullable(this DataContract collectionDataContract) { if (collectionDataContract.GetContractType() == DataContractType.CollectionDataContract) { // This would be easier if we had included a way to read 'IsItemTypeNullable' from // CollectionDataContract. But let's do our best to see if we can figure out the // nullability of the collection item type. // If the item type is not a value type, then it's nullable. // Dictionary KeyValuePair's are imported as value types. DataContract itemContract = collectionDataContract.BaseContract!; if (!itemContract.IsValueType) return true; // GetArrayTypeName() generates the default DCS stable XML name for a collection of this item contract // One of these variants should match for our item type, unless the imported schema is using a non-standard // XML name for the collection item type. // First check the standard non-nullable collection XML name for this item type. XmlQualifiedName nonNullableCollectionType = itemContract.GetArrayTypeName(isNullable: false); if (collectionDataContract.XmlName.Name == nonNullableCollectionType.Name && collectionDataContract.XmlName.Namespace == nonNullableCollectionType.Namespace) { return false; } // Then check the standard nullable collection XML name for this item type. XmlQualifiedName nullableCollectionType = itemContract.GetArrayTypeName(isNullable: true); if (collectionDataContract.XmlName.Name == nullableCollectionType.Name && collectionDataContract.XmlName.Namespace == nullableCollectionType.Namespace) { return true; } // If we get here, then the collection is using non-standard XML naming. // UnderlyingType might be an actual CLR type, or it might be the SchemaDefinedType placeholder. // This is just a best effort attempt at this point. return SchemaImportHelper.IsTypeNullable(itemContract.UnderlyingType); } return false; } } internal static class SchemaImportHelper { internal static bool IsTypeNullable(Type type) { return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } internal static string GetCollectionNamespace(string elementNs) { return IsBuiltInNamespace(elementNs) ? ImportGlobals.CollectionsNamespace : elementNs; } internal static string GetDataContractNamespaceFromUri(string uriString) { return uriString.StartsWith(ImportGlobals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(ImportGlobals.DataContractXsdBaseNamespace.Length) : uriString; } internal static string GetDefaultXmlNamespace(string? clrNs) { return new Uri(ImportGlobals.DataContractXsdBaseNamespaceUri, clrNs ?? string.Empty).AbsoluteUri; } internal static bool IsBuiltInNamespace(string ns) { return (ns == ImportGlobals.SchemaNamespace || ns == ImportGlobals.SerializationNamespace); } // This should match the behavior of DataContract.EncodeLocalName internal static string EncodeLocalName(string localName) { if (IsAsciiLocalName(localName)) return localName; if (IsValidNCName(localName)) return localName; return XmlConvert.EncodeLocalName(localName); } private static bool IsAsciiLocalName(string localName) { if (localName.Length == 0) return false; if (!char.IsAsciiLetter(localName[0])) return false; for (int i = 1; i < localName.Length; i++) { char ch = localName[i]; if (!char.IsAsciiLetterOrDigit(ch)) return false; } return true; } private static bool IsValidNCName(string name) { try { XmlConvert.VerifyNCName(name); return true; } catch (XmlException) { return false; } } } }