diff --git a/README.md b/README.md
index f58f996d..a41cec55 100644
--- a/README.md
+++ b/README.md
@@ -149,6 +149,9 @@ Options:
(default is true)
--nc, --netCore generate .NET Core specific code that might not
work with .NET Framework (default is false)
+ --nr, --nullableReferenceAttributes
+ generate attributes for nullable reference types (
+ default is false)
--ar, --useArrayItemAttribute
use ArrayItemAttribute for sequences with single
elements (default is true)
diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs
index 0216e8d5..33549254 100644
--- a/XmlSchemaClassGenerator.Tests/XmlTests.cs
+++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs
@@ -2399,7 +2399,7 @@ void assertNullable(string typename, bool nullable)
Assert.Equal(nullable, hasMaybeNullAttribute);
}
assertNullable("Test.ElementReferenceNullable", true);
- assertNullable("Test.ElementReferenceList", true);
+ assertNullable("Test.ElementReferenceList", false);
assertNullable("Test.ElementReferenceNonNullable", false);
assertNullable("Test.AttributeReferenceNullable", true);
assertNullable("Test.AttributeReferenceNonNullable", false);
diff --git a/XmlSchemaClassGenerator.Tests/xsd/simple/recursive.xsd b/XmlSchemaClassGenerator.Tests/xsd/simple/recursive.xsd
new file mode 100644
index 00000000..11832ad8
--- /dev/null
+++ b/XmlSchemaClassGenerator.Tests/xsd/simple/recursive.xsd
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/XmlSchemaClassGenerator/CodeUtilities.cs b/XmlSchemaClassGenerator/CodeUtilities.cs
index 6f87d805..adbda9cc 100644
--- a/XmlSchemaClassGenerator/CodeUtilities.cs
+++ b/XmlSchemaClassGenerator/CodeUtilities.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Schema;
@@ -12,165 +13,88 @@ namespace XmlSchemaClassGenerator
public static class CodeUtilities
{
// Match non-letter followed by letter
- static readonly Regex PascalCaseRegex = new(@"[^\p{L}]\p{L}", RegexOptions.Compiled);
+ private static readonly Regex PascalCaseRegex = new(@"[^\p{L}]\p{L}", RegexOptions.Compiled);
// Uppercases first letter and all letters following non-letters.
// Examples: testcase -> Testcase, html5element -> Html5Element, test_case -> Test_Case
- public static string ToPascalCase(this string s)
- {
- if (string.IsNullOrEmpty(s)) { return s; }
- return char.ToUpperInvariant(s[0])
- + PascalCaseRegex.Replace(s.Substring(1), m => m.Value[0] + char.ToUpperInvariant(m.Value[1]).ToString());
- }
+ public static string ToPascalCase(this string s) => string.IsNullOrEmpty(s) ? s
+ : char.ToUpperInvariant(s[0]) + PascalCaseRegex.Replace(s.Substring(1), m => m.Value[0] + char.ToUpperInvariant(m.Value[1]).ToString());
- public static string ToCamelCase(this string s)
- {
- if (string.IsNullOrEmpty(s)) { return s; }
- return char.ToLowerInvariant(s[0]) + s.Substring(1);
- }
+ public static string ToCamelCase(this string s) => string.IsNullOrEmpty(s) ? s
+ : char.ToLowerInvariant(s[0]) + s.Substring(1);
public static string ToBackingField(this string propertyName, string privateFieldPrefix)
- {
- return string.Concat(privateFieldPrefix, propertyName.ToCamelCase());
- }
+ => string.Concat(privateFieldPrefix, propertyName.ToCamelCase());
- public static bool? IsDataTypeAttributeAllowed(this XmlSchemaDatatype type)
+ public static bool? IsDataTypeAttributeAllowed(this XmlSchemaDatatype type) => type.TypeCode switch
{
- bool? result = type.TypeCode switch
- {
- XmlTypeCode.AnyAtomicType => false,// union
- XmlTypeCode.DateTime or XmlTypeCode.Time or XmlTypeCode.Date or XmlTypeCode.Base64Binary or XmlTypeCode.HexBinary => true,
- _ => false,
- };
-
- return result;
- }
+ XmlTypeCode.AnyAtomicType => false,// union
+ XmlTypeCode.DateTime or XmlTypeCode.Time or XmlTypeCode.Date or XmlTypeCode.Base64Binary or XmlTypeCode.HexBinary => true,
+ _ => false,
+ };
- private static Type GetIntegerDerivedType(XmlSchemaDatatype type, GeneratorConfiguration configuration, IEnumerable restrictions)
+ private static Type GetIntegerDerivedType(XmlSchemaDatatype xml, GeneratorConfiguration configuration, IEnumerable restrictions)
{
if (configuration.IntegerDataType != null && !configuration.UseIntegerDataTypeAsFallback) return configuration.IntegerDataType;
- var xmlTypeCode = type.TypeCode;
-
- Type result = null;
-
- var maxInclusive = restrictions.OfType().SingleOrDefault();
- var minInclusive = restrictions.OfType().SingleOrDefault();
-
- decimal? maxInclusiveValue = null;
- if (maxInclusive is null && xmlTypeCode == XmlTypeCode.NegativeInteger)
+ decimal? maxInclusive = (restrictions.OfType().SingleOrDefault(), xml.TypeCode) switch
{
- maxInclusiveValue = -1;
- }
- else if (maxInclusive is null && xmlTypeCode == XmlTypeCode.NonPositiveInteger)
- {
- maxInclusiveValue = 0;
- }
- else if (maxInclusive != null && decimal.TryParse(maxInclusive.Value, out decimal value))
- {
- maxInclusiveValue = value;
- }
+ (null, XmlTypeCode.NegativeInteger) => -1,
+ (null, XmlTypeCode.NonPositiveInteger) => 0,
+ ({ Value: var str }, _) when decimal.TryParse(str, out decimal value) => value,
+ _ => null,
+ };
- decimal? minInclusiveValue = null;
- if (minInclusive is null && xmlTypeCode == XmlTypeCode.PositiveInteger)
- {
- minInclusiveValue = 1;
- }
- else if (minInclusive is null && xmlTypeCode == XmlTypeCode.NonNegativeInteger)
+ decimal? minInclusive = (restrictions.OfType().SingleOrDefault(), xml.TypeCode) switch
{
- minInclusiveValue = 0;
- }
- else if (minInclusive != null && decimal.TryParse(minInclusive.Value, out decimal value))
- {
- minInclusiveValue = value;
- }
+ (null, XmlTypeCode.PositiveInteger) => 1,
+ (null, XmlTypeCode.NonNegativeInteger) => 0,
+ ({ Value: var str }, _) when decimal.TryParse(str, out decimal value) => value,
+ _ => null,
+ };
// If either value is null, then that value is either unbounded or too large to fit in any numeric type.
- if (minInclusiveValue != null && maxInclusiveValue != null) {
- if (minInclusiveValue >= byte.MinValue && maxInclusiveValue <= byte.MaxValue)
- result = typeof(byte);
- else if (minInclusiveValue >= sbyte.MinValue && maxInclusiveValue <= sbyte.MaxValue)
- result = typeof(sbyte);
- else if (minInclusiveValue >= ushort.MinValue && maxInclusiveValue <= ushort.MaxValue)
- result = typeof(ushort);
- else if (minInclusiveValue >= short.MinValue && maxInclusiveValue <= short.MaxValue)
- result = typeof(short);
- else if (minInclusiveValue >= uint.MinValue && maxInclusiveValue <= uint.MaxValue)
- result = typeof(uint);
- else if (minInclusiveValue >= int.MinValue && maxInclusiveValue <= int.MaxValue)
- result = typeof(int);
- else if (minInclusiveValue >= ulong.MinValue && maxInclusiveValue <= ulong.MaxValue)
- result = typeof(ulong);
- else if (minInclusiveValue >= long.MinValue && maxInclusiveValue <= long.MaxValue)
- result = typeof(long);
- else // If it didn't fit in a decimal, we could not have gotten here.
- result = typeof(decimal);
-
- return result;
- }
+ return FromMinMax() ?? FromDigitRestriction(restrictions.OfType().SingleOrDefault()) ?? FromFallback();
- if (restrictions.SingleOrDefault(r => r is TotalDigitsRestrictionModel) is not TotalDigitsRestrictionModel totalDigits
- || ((xmlTypeCode == XmlTypeCode.PositiveInteger
- || xmlTypeCode == XmlTypeCode.NonNegativeInteger) && totalDigits.Value >= 30)
- || ((xmlTypeCode == XmlTypeCode.Integer
- || xmlTypeCode == XmlTypeCode.NegativeInteger
- || xmlTypeCode == XmlTypeCode.NonPositiveInteger) && totalDigits.Value >= 29))
+ Type FromMinMax() => (minInclusive, maxInclusive) switch
{
- if (configuration.UseIntegerDataTypeAsFallback && configuration.IntegerDataType != null)
- return configuration.IntegerDataType;
- return typeof(string);
- }
+ (null, _) => null,
+ (_, null) => null,
+ ( >= byte.MinValue, <= byte.MaxValue) => typeof(byte),
+ ( >= sbyte.MinValue, <= sbyte.MaxValue) => typeof(sbyte),
+ ( >= ushort.MinValue, <= ushort.MaxValue) => typeof(ushort),
+ ( >= short.MinValue, <= short.MaxValue) => typeof(short),
+ ( >= uint.MinValue, <= uint.MaxValue) => typeof(uint),
+ ( >= int.MinValue, <= int.MaxValue) => typeof(int),
+ ( >= ulong.MinValue, <= ulong.MaxValue) => typeof(ulong),
+ ( >= long.MinValue, <= long.MaxValue) => typeof(long),
+ _ => typeof(decimal),
+ };
- switch (xmlTypeCode)
+ Type FromDigitRestriction(TotalDigitsRestrictionModel totalDigits) => xml.TypeCode switch
{
- case XmlTypeCode.PositiveInteger:
- case XmlTypeCode.NonNegativeInteger:
- switch (totalDigits.Value)
- {
- case int n when (n < 3):
- result = typeof(byte);
- break;
- case int n when (n < 5):
- result = typeof(ushort);
- break;
- case int n when (n < 10):
- result = typeof(uint);
- break;
- case int n when (n < 20):
- result = typeof(ulong);
- break;
- case int n when (n < 30):
- result = typeof(decimal);
- break;
- }
-
- break;
-
- case XmlTypeCode.Integer:
- case XmlTypeCode.NegativeInteger:
- case XmlTypeCode.NonPositiveInteger:
- switch (totalDigits.Value)
- {
- case int n when (n < 3):
- result = typeof(sbyte);
- break;
- case int n when (n < 5):
- result = typeof(short);
- break;
- case int n when (n < 10):
- result = typeof(int);
- break;
- case int n when (n < 19):
- result = typeof(long);
- break;
- case int n when (n < 29):
- result = typeof(decimal);
- break;
- }
- break;
- }
+ XmlTypeCode.PositiveInteger or XmlTypeCode.NonNegativeInteger => totalDigits?.Value switch
+ {
+ < 3 => typeof(byte),
+ < 5 => typeof(ushort),
+ < 10 => typeof(uint),
+ < 20 => typeof(ulong),
+ < 30 => typeof(decimal),
+ _ => null
+ },
+ XmlTypeCode.Integer or XmlTypeCode.NegativeInteger or XmlTypeCode.NonPositiveInteger => totalDigits?.Value switch
+ {
+ < 3 => typeof(sbyte),
+ < 5 => typeof(short),
+ < 10 => typeof(int),
+ < 19 => typeof(long),
+ < 29 => typeof(decimal),
+ _ => null
+ },
+ _ => null,
+ };
- return result;
+ Type FromFallback() => configuration.UseIntegerDataTypeAsFallback && configuration.IntegerDataType != null ? configuration.IntegerDataType : typeof(string);
}
public static Type GetEffectiveType(this XmlSchemaDatatype type, GeneratorConfiguration configuration, IEnumerable restrictions, bool attribute = false)
@@ -217,21 +141,14 @@ public static XmlQualifiedName GetQualifiedName(this TypeModel typeModel)
XmlQualifiedName qualifiedName;
if (typeModel is not SimpleModel simpleTypeModel)
{
- if (typeModel.IsAnonymous)
- {
- qualifiedName = typeModel.XmlSchemaName;
- }
- else
- {
- qualifiedName = typeModel.XmlSchemaType.GetQualifiedName();
- }
+ qualifiedName = typeModel.IsAnonymous ? typeModel.XmlSchemaName
+ : typeModel.XmlSchemaType.GetQualifiedName();
}
else
{
qualifiedName = simpleTypeModel.XmlSchemaType.GetQualifiedName();
var xmlSchemaType = simpleTypeModel.XmlSchemaType;
- while (qualifiedName.Namespace != XmlSchema.Namespace &&
- xmlSchemaType.BaseXmlSchemaType != null)
+ while (qualifiedName.Namespace != XmlSchema.Namespace && xmlSchemaType.BaseXmlSchemaType != null)
{
xmlSchemaType = xmlSchemaType.BaseXmlSchemaType;
qualifiedName = xmlSchemaType.GetQualifiedName();
@@ -243,13 +160,9 @@ public static XmlQualifiedName GetQualifiedName(this TypeModel typeModel)
public static string GetUniqueTypeName(this NamespaceModel model, string name)
{
var n = name;
- var i = 2;
- while (model.Types.ContainsKey(n) && model.Types[n] is not SimpleModel)
- {
+ for (var i = 2; model.Types.ContainsKey(n) && model.Types[n] is not SimpleModel; i++)
n = name + i;
- i++;
- }
return n;
}
@@ -259,90 +172,49 @@ public static string GetUniqueFieldName(this TypeModel typeModel, PropertyModel
var classModel = typeModel as ClassModel;
var propBackingFieldName = propertyModel.Name.ToBackingField(classModel?.Configuration.PrivateMemberPrefix);
- if (CSharpKeywords.Contains(propBackingFieldName.ToLower()))
+ if (!IsValidIdentifier(propBackingFieldName.ToLower()))
propBackingFieldName = "@" + propBackingFieldName;
if (classModel == null)
- {
return propBackingFieldName;
- }
var i = 0;
foreach (var prop in classModel.Properties)
{
if (propertyModel == prop)
{
- i += 1;
+ i++;
break;
}
var backingFieldName = prop.Name.ToBackingField(classModel.Configuration.PrivateMemberPrefix);
if (backingFieldName == propBackingFieldName)
- {
- i += 1;
- }
+ i++;
}
- if (i <= 1)
- {
- return propBackingFieldName;
- }
-
- return string.Format("{0}{1}", propBackingFieldName, i);
+ return i <= 1 ? propBackingFieldName : $"{propBackingFieldName}{i}";
}
public static string GetUniquePropertyName(this TypeModel tm, string name)
{
- if (tm is ClassModel cls)
- {
- var i = 0;
- var n = name;
- var baseClasses = cls.AllBaseClasses.ToList();
- var props = cls.Properties.ToList();
-
- while (baseClasses.SelectMany(b => b.Properties)
- .Concat(props)
- .Any(p => p.Name == n))
- {
- n = name + (++i);
- }
+ if (tm is not ClassModel cls) return name;
- return n;
- }
+ var i = 0;
+ var n = name;
+ var baseProps = cls.AllBaseClasses.SelectMany(b => b.Properties).ToList();
+ var props = cls.Properties.ToList();
+
+ while (baseProps.Concat(props).Any(p => p.Name == n))
+ n = name + (++i);
- return name;
+ return n;
}
- static readonly Regex NormalizeNewlinesRegex = new (@"(^|[^\r])\n", RegexOptions.Compiled);
+ private static readonly Regex NormalizeNewlinesRegex = new(@"(^|[^\r])\n", RegexOptions.Compiled);
- internal static string NormalizeNewlines(string text)
- {
- return NormalizeNewlinesRegex.Replace(text, "$1\r\n");
- }
+ internal static string NormalizeNewlines(string text) => NormalizeNewlinesRegex.Replace(text, "$1\r\n");
- static readonly List CSharpKeywords = new()
- {
- "abstract", "as", "base", "bool",
- "break", "byte", "case", "catch",
- "char", "checked", "class", "const",
- "continue", "decimal", "default", "delegate",
- "do", "double", "else", "enum",
- "event", " explicit", "extern", "false",
- "finally", "fixed", "float", "for",
- "foreach", "goto", "if", "implicit",
- "in", "int", "interface", "internal",
- "is", "lock", "long", "namespace",
- "new", "null", "object", "operator",
- "out", "override", "params", "private",
- "protected", "public", "readonly", "ref",
- "return", "sbyte", "sealed", "short",
- "sizeof", "stackalloc", "static", "string",
- "struct", "switch", "this", "throw",
- "true", "try", "typeof", "uint",
- "ulong", "unchecked", "unsafe", "ushort",
- "using", "using static", "virtual", "void",
- "volatile", "while"
- };
+ private static readonly Predicate IsValidIdentifier = new Microsoft.CSharp.CSharpCodeProvider().IsValidIdentifier;
internal static Uri CreateUri(string uri) => string.IsNullOrEmpty(uri) ? null : new Uri(uri);
@@ -350,9 +222,7 @@ public static KeyValuePair ParseNamespace(string nsArg, st
{
var parts = nsArg.Split(new[] { '=' }, 2);
if (parts.Length != 2)
- {
throw new ArgumentException("XML and C# namespaces should be separated by '='. You entered: " + nsArg);
- }
var xmlNs = parts[0];
var netNs = parts[1];
@@ -360,13 +230,12 @@ public static KeyValuePair ParseNamespace(string nsArg, st
var source = parts2.Length == 2 ? new Uri(parts2[1], UriKind.RelativeOrAbsolute) : null;
xmlNs = parts2[0];
if (!string.IsNullOrEmpty(namespacePrefix))
- {
netNs = namespacePrefix + "." + netNs;
- }
+
return new KeyValuePair(new NamespaceKey(source, xmlNs), netNs);
}
- public static readonly ImmutableList<(string Namespace, Func Condition)> UsingNamespaces = ImmutableList.Create<(string Namespace, Func Condition)>(
+ public static readonly ImmutableList<(string Namespace, Func Condition)> UsingNamespaces = ImmutableList.Create<(string, Func)>(
("System", c => c.CompactTypeNames),
("System.CodeDom.Compiler", c => c.CompactTypeNames),
("System.Collections.Generic", c => c.CompactTypeNames),
@@ -374,26 +243,25 @@ public static KeyValuePair ParseNamespace(string nsArg, st
("System.ComponentModel", c => c.CompactTypeNames),
("System.ComponentModel.DataAnnotations", c => c.CompactTypeNames && (c.DataAnnotationMode != DataAnnotationMode.None || c.EntityFramework)),
("System.Diagnostics", c => c.CompactTypeNames && c.GenerateDebuggerStepThroughAttribute),
+ ("System.Diagnostics.CodeAnalysis", c => c.CompactTypeNames && c.EnableNullableReferenceAttributes),
("System.Linq", c => c.EnableDataBinding),
("System.Xml", c => c.CompactTypeNames),
("System.Xml.Schema", c => c.CompactTypeNames),
("System.Xml.Serialization", c => c.CompactTypeNames)
);
- public static bool IsUsingNamespace(Type t, GeneratorConfiguration conf) => UsingNamespaces.Any(n => n.Namespace == t.Namespace && n.Condition(conf));
-
- public static bool IsUsingNamespace(string namespaceName, GeneratorConfiguration conf) => UsingNamespaces.Any(n => n.Namespace == namespaceName && n.Condition(conf));
+ public static bool IsUsingNamespace(string namespaceName, GeneratorConfiguration conf)
+ => UsingNamespaces.Any(n => n.Namespace == namespaceName && n.Condition(conf));
- public static CodeTypeReference CreateTypeReference(Type t, GeneratorConfiguration conf)
+ public static CodeTypeReference CreateTypeReference(Type type, GeneratorConfiguration conf)
{
- if (IsUsingNamespace(t, conf))
+ if (IsUsingNamespace(type.Namespace, conf))
{
- var name = t.Name;
- var typeRef = new CodeTypeReference(name, conf.CodeTypeReferenceOptions);
+ var typeRef = new CodeTypeReference(type.Name, conf.CodeTypeReferenceOptions);
- if (t.IsConstructedGenericType)
+ if (type.IsConstructedGenericType)
{
- var typeArgs = t.GenericTypeArguments.Select(a => CreateTypeReference(a, conf)).ToArray();
+ var typeArgs = type.GenericTypeArguments.Select(a => CreateTypeReference(a, conf)).ToArray();
typeRef.TypeArguments.AddRange(typeArgs);
}
@@ -401,31 +269,20 @@ public static CodeTypeReference CreateTypeReference(Type t, GeneratorConfigurati
}
else
{
- var typeRef = new CodeTypeReference(t, conf.CodeTypeReferenceOptions);
+ var typeRef = new CodeTypeReference(type, conf.CodeTypeReferenceOptions);
- foreach (var typeArg in typeRef.TypeArguments)
- {
- if (typeArg is CodeTypeReference typeArgRef)
- {
- typeArgRef.Options = conf.CodeTypeReferenceOptions;
- }
- }
+ foreach (var typeArgRef in typeRef.TypeArguments.OfType())
+ typeArgRef.Options = conf.CodeTypeReferenceOptions;
return typeRef;
}
-
}
- public static CodeTypeReference CreateTypeReference(string namespaceName, string typeName, GeneratorConfiguration conf)
+ public static CodeTypeReference CreateTypeReference(TypeInfo type, GeneratorConfiguration conf)
{
- if (IsUsingNamespace(namespaceName, conf))
- {
- var typeRef = new CodeTypeReference(typeName, conf.CodeTypeReferenceOptions);
-
- return typeRef;
- }
- else
- return new CodeTypeReference($"{namespaceName}.{typeName}", conf.CodeTypeReferenceOptions);
+ return IsUsingNamespace(type.Namespace, conf)
+ ? new CodeTypeReference(type.Name, conf.CodeTypeReferenceOptions)
+ : new CodeTypeReference($"{type.Namespace}.{type.Name}", conf.CodeTypeReferenceOptions);
}
///
@@ -433,21 +290,42 @@ public static CodeTypeReference CreateTypeReference(string namespaceName, string
/// and https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlattributeattribute#remarks
///
public static bool IsXmlLangOrSpace(XmlQualifiedName name)
- {
- return name != null && name.Namespace == "http://www.w3.org/XML/1998/namespace"
- && (name.Name == "lang" || name.Name == "space");
- }
+ => name?.Namespace == "http://www.w3.org/XML/1998/namespace" && (name.Name == "lang" || name.Name == "space");
- internal static XmlQualifiedName GetQualifiedName(this XmlSchemaObject obj)
+ internal static XmlQualifiedName GetQualifiedName(this XmlSchemaObject obj) => obj switch
{
- var n = obj switch
- {
- XmlSchemaAttribute attr => attr.QualifiedName,
- XmlSchemaAttributeGroup attrGroup => attrGroup.QualifiedName,
- _ => null
- };
+ XmlSchemaAttribute attr => attr.QualifiedName,
+ XmlSchemaAttributeGroup attrGroup => attrGroup.QualifiedName,
+ _ => null
+ };
+ }
- return n;
- }
+ public readonly record struct TypeInfo(string Namespace, string Name);
+
+ ///
+ /// For attributes which can't be referenced by typeof()
+ ///
+ internal static class Attributes
+ {
+ private const string DataAnnotations = "System.ComponentModel.DataAnnotations";
+ private const string CodeAnalysis = "System.Diagnostics.CodeAnalysis";
+
+ private static TypeInfo Make(string @namespace, [CallerMemberName] string name = null)
+ => new(@namespace, name + "Attribute");
+
+ public static TypeInfo Required { get; } = Make(DataAnnotations);
+ public static TypeInfo Key { get; } = Make(DataAnnotations);
+ public static TypeInfo Range { get; } = Make(DataAnnotations);
+ public static TypeInfo MinLength { get; } = Make(DataAnnotations);
+ public static TypeInfo MaxLength { get; } = Make(DataAnnotations);
+ public static TypeInfo StringLength { get; } = Make(DataAnnotations);
+ public static TypeInfo RegularExpression { get; } = Make(DataAnnotations);
+ public static TypeInfo NotMapped { get; } = Make($"{DataAnnotations}.Schema");
+
+ public static TypeInfo AllowNull { get; } = Make(CodeAnalysis);
+ public static TypeInfo MaybeNull { get; } = Make(CodeAnalysis);
}
-}
\ No newline at end of file
+}
+
+//Fixes a bug with VS2019 (https://developercommunity.visualstudio.com/content/problem/1244809/error-cs0518-predefined-type-systemruntimecompiler.html)
+namespace System.Runtime.CompilerServices { internal static class IsExternalInit { } }
\ No newline at end of file
diff --git a/XmlSchemaClassGenerator/ModelBuilder.cs b/XmlSchemaClassGenerator/ModelBuilder.cs
index a2c97c8d..b6b81073 100644
--- a/XmlSchemaClassGenerator/ModelBuilder.cs
+++ b/XmlSchemaClassGenerator/ModelBuilder.cs
@@ -29,7 +29,7 @@ public ModelBuilder(GeneratorConfiguration configuration, XmlSchemaSet set)
_configuration = configuration;
_set = set;
- DocumentationModel.DisableComments = _configuration.DisableComments;
+ GeneratorModel.DisableComments = _configuration.DisableComments;
var objectModel = new SimpleModel(_configuration)
{
Name = "AnyType",
@@ -380,7 +380,7 @@ private IEnumerable GetSubstitutedElements(XmlQualifiedName name)
{
if (SubstitutionGroups.TryGetValue(name, out var substitutes))
{
- foreach (var substitute in substitutes)
+ foreach (var substitute in substitutes.Where(s => s.Element.QualifiedName != name))
{
yield return substitute;
foreach (var recursiveSubstitute in GetSubstitutedElements(substitute.Element.QualifiedName))
diff --git a/XmlSchemaClassGenerator/RestrictionModel.cs b/XmlSchemaClassGenerator/RestrictionModel.cs
index 79c57be5..1976ef85 100644
--- a/XmlSchemaClassGenerator/RestrictionModel.cs
+++ b/XmlSchemaClassGenerator/RestrictionModel.cs
@@ -1,28 +1,13 @@
using System;
using System.CodeDom;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace XmlSchemaClassGenerator
{
- public abstract class RestrictionModel
+ public abstract class RestrictionModel : GeneratorModel
{
- public GeneratorConfiguration Configuration { get; private set; }
+ protected RestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- protected RestrictionModel(GeneratorConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public bool IsSupported
- {
- get
- {
- return MinimumDataAnnotationMode >= Configuration.DataAnnotationMode;
- }
- }
+ public bool IsSupported => MinimumDataAnnotationMode >= Configuration.DataAnnotationMode;
///
/// The DataAnnotationMode required to be able to emit this restriction
@@ -34,281 +19,126 @@ public bool IsSupported
public abstract class ValueRestrictionModel : RestrictionModel
{
- protected ValueRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ protected ValueRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
public T Value { get; set; }
- public override CodeAttributeDeclaration GetAttribute()
- {
- return null;
- }
+ public override CodeAttributeDeclaration GetAttribute() => null;
}
- public abstract class ValueTypeRestrictionModel: ValueRestrictionModel
+ public abstract class ValueTypeRestrictionModel : ValueRestrictionModel
{
- protected ValueTypeRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ protected ValueTypeRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
public Type Type { get; set; }
}
public class MinMaxLengthRestrictionModel : RestrictionModel
{
- public MinMaxLengthRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ public MinMaxLengthRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
public int Min { get; set; }
public int Max { get; set; }
- public override string Description
- {
- get
- {
- var s = "";
- if (Min > 0) { s += string.Format("Minimum length: {0}. ", Min); }
- if (Max > 0) { s += string.Format("Maximum length: {0}.", Max); }
- return s.Trim();
- }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.Partial;
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.Partial; }
- }
+ public override string Description => ((Min > 0 ? $"Minimum length: {Min}. " : string.Empty) + (Max > 0 ? $"Maximum length: {Max}." : string.Empty)).Trim();
public override CodeAttributeDeclaration GetAttribute()
{
- var a = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "StringLengthAttribute", Configuration),
- new CodeAttributeArgument(Max > 0 ? (CodeExpression)new CodePrimitiveExpression(Max) : new CodeSnippetExpression("int.MaxValue")));
- if (Min > 0) { a.Arguments.Add(new CodeAttributeArgument("MinimumLength", new CodePrimitiveExpression(Min))); }
-
+ var a = AttributeDecl(Attributes.StringLength, new(Max > 0 ? new CodePrimitiveExpression(Max) : new CodeSnippetExpression("int.MaxValue")));
+ if (Min > 0) { a.Arguments.Add(new("MinimumLength", new CodePrimitiveExpression(Min))); }
return a;
}
}
public class MaxLengthRestrictionModel : ValueRestrictionModel
{
- public MaxLengthRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public MaxLengthRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
-
- public override string Description
- {
- get
- {
- return string.Format("Maximum length: {0}.", Value);
- }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
+ public override string Description => string.Format("Maximum length: {0}.", Value);
public override CodeAttributeDeclaration GetAttribute()
- {
- return new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "MaxLengthAttribute", Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(Value)));
- }
+ => AttributeDecl(Attributes.MaxLength, new(new CodePrimitiveExpression(Value)));
}
public class MinLengthRestrictionModel : ValueRestrictionModel
{
- public MinLengthRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public MinLengthRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override string Description
- {
- get
- {
- return string.Format("Minimum length: {0}.", Value);
- }
- }
-
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
+ public override string Description => string.Format("Minimum length: {0}.", Value);
public override CodeAttributeDeclaration GetAttribute()
- {
- return new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "MinLengthAttribute", Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(Value)));
- }
+ => AttributeDecl(Attributes.MinLength, new(new CodePrimitiveExpression(Value)));
}
public class TotalDigitsRestrictionModel : ValueRestrictionModel
{
- public TotalDigitsRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public TotalDigitsRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
-
- public override string Description
- {
- get
- {
- return string.Format("Total number of digits: {0}.", Value);
- }
- }
+ public override string Description => string.Format("Total number of digits: {0}.", Value);
}
public class FractionDigitsRestrictionModel : ValueRestrictionModel
{
- public FractionDigitsRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ public FractionDigitsRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override string Description
- {
- get
- {
- return string.Format("Total number of digits in fraction: {0}.", Value);
- }
- }
+ public override string Description => $"Total number of digits in fraction: {Value}.";
}
public class PatternRestrictionModel : ValueRestrictionModel
{
- public PatternRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public PatternRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.Partial;
- public override string Description
- {
- get
- {
- return string.Format("Pattern: {0}.", Value);
- }
- }
-
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.Partial; }
- }
+ public override string Description => $"Pattern: {Value}.";
public override CodeAttributeDeclaration GetAttribute()
- {
- return new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "RegularExpressionAttribute", Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(Value)));
- }
+ => AttributeDecl(Attributes.RegularExpression, new(new CodePrimitiveExpression(Value)));
}
- public class MinInclusiveRestrictionModel: ValueTypeRestrictionModel
+ public class MinInclusiveRestrictionModel : ValueTypeRestrictionModel
{
- public MinInclusiveRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public MinInclusiveRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
-
- public override string Description
- {
- get
- {
- return string.Format("Minimum inclusive value: {0}.", Value);
- }
- }
+ public override string Description => $"Minimum inclusive value: {Value}.";
}
- public class MinExclusiveRestrictionModel: ValueTypeRestrictionModel
+ public class MinExclusiveRestrictionModel : ValueTypeRestrictionModel
{
- public MinExclusiveRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ public MinExclusiveRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override string Description
- {
- get
- {
- return string.Format("Minimum exclusive value: {0}.", Value);
- }
- }
+ public override string Description => $"Minimum exclusive value: {Value}.";
}
- public class MaxInclusiveRestrictionModel: ValueTypeRestrictionModel
+ public class MaxInclusiveRestrictionModel : ValueTypeRestrictionModel
{
- public MaxInclusiveRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
-
- }
+ public MaxInclusiveRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override string Description
- {
- get
- {
- return string.Format("Maximum inclusive value: {0}.", Value);
- }
- }
+ public override string Description => $"Maximum inclusive value: {Value}.";
}
- public class MaxExclusiveRestrictionModel: ValueTypeRestrictionModel
+ public class MaxExclusiveRestrictionModel : ValueTypeRestrictionModel
{
- public MaxExclusiveRestrictionModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
+ public MaxExclusiveRestrictionModel(GeneratorConfiguration configuration) : base(configuration) { }
- }
+ public override DataAnnotationMode MinimumDataAnnotationMode => DataAnnotationMode.All;
- public override DataAnnotationMode MinimumDataAnnotationMode
- {
- get { return DataAnnotationMode.All; }
- }
-
- public override string Description
- {
- get
- {
- return string.Format("Maximum exclusive value: {0}.", Value);
- }
- }
+ public override string Description => $"Maximum exclusive value: {Value}.";
}
}
diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs
index afb8714b..2f1f78c0 100644
--- a/XmlSchemaClassGenerator/TypeModel.cs
+++ b/XmlSchemaClassGenerator/TypeModel.cs
@@ -13,20 +13,18 @@
namespace XmlSchemaClassGenerator
{
- public class NamespaceModel
+ public class NamespaceModel : GeneratorModel
{
public string Name { get; set; }
- public NamespaceKey Key { get; private set; }
+ public NamespaceKey Key { get; }
public Dictionary Types { get; set; }
///
/// Does the namespace of this type clashes with a class in the same or upper namespace?
///
public bool IsAmbiguous { get; set; }
- public GeneratorConfiguration Configuration { get; private set; }
- public NamespaceModel(NamespaceKey key, GeneratorConfiguration configuration)
+ public NamespaceModel(NamespaceKey key, GeneratorConfiguration configuration) : base(configuration)
{
- Configuration = configuration;
Key = key;
Types = new Dictionary();
}
@@ -38,9 +36,7 @@ public static CodeNamespace Generate(string namespaceName, IEnumerable n.Condition(conf)).OrderBy(n => n.Namespace))
codeNamespace.Imports.Add(new CodeNamespaceImport(Namespace));
- var typeModels = parts.SelectMany(x => x.Types.Values).ToList();
-
- foreach (var typeModel in typeModels)
+ foreach (var typeModel in parts.SelectMany(x => x.Types.Values).ToList())
{
var type = typeModel.Generate();
if (type != null)
@@ -57,53 +53,10 @@ public class DocumentationModel
{
public string Language { get; set; }
public string Text { get; set; }
- public static bool DisableComments { get; set; }
-
- public static IEnumerable GetComments(IList docs, GeneratorConfiguration conf)
- {
- if (DisableComments || docs.Count == 0)
- yield break;
-
- yield return new CodeCommentStatement("", true);
-
- foreach (var doc in docs
- .Where(d => string.IsNullOrEmpty(d.Language) || conf.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase)))
- .OrderBy(d => d.Language))
- {
- var text = doc.Text;
- var comment = string.Format(@"{1}",
- string.IsNullOrEmpty(doc.Language) ? "" : string.Format(@" xml:lang=""{0}""", doc.Language), CodeUtilities.NormalizeNewlines(text).Trim());
- yield return new CodeCommentStatement(comment, true);
- }
-
- yield return new CodeCommentStatement("", true);
- }
-
- public static void AddDescription(CodeAttributeDeclarationCollection attributes, IEnumerable docs, GeneratorConfiguration conf)
- {
- if (!conf.GenerateDescriptionAttribute || DisableComments || !docs.Any()) return;
-
- var doc = GetSingleDoc(docs.Where(d => string.IsNullOrEmpty(d.Language) || conf.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))));
-
- if (doc != null)
- {
- var descriptionAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(DescriptionAttribute), conf),
- new CodeAttributeArgument(new CodePrimitiveExpression(Regex.Replace(doc.Text, @"\s+", " ").Trim())));
- attributes.Add(descriptionAttribute);
- }
- }
-
- private static DocumentationModel GetSingleDoc(IEnumerable docs)
- {
- if (docs.Count() == 1) return docs.Single();
- var englishDoc = docs.FirstOrDefault(d => string.IsNullOrEmpty(d.Language) || d.Language.StartsWith("en", StringComparison.OrdinalIgnoreCase));
- if (englishDoc != null) return englishDoc;
- return docs.FirstOrDefault();
- }
}
[DebuggerDisplay("{Name}")]
- public abstract class TypeModel
+ public abstract class TypeModel : GeneratorModel
{
protected static readonly CodeDomProvider CSharpProvider = CodeDomProvider.CreateProvider("CSharp");
@@ -114,28 +67,23 @@ public abstract class TypeModel
public string Name { get; set; }
public XmlQualifiedName XmlSchemaName { get; set; }
public XmlSchemaType XmlSchemaType { get; set; }
- public List Documentation { get; private set; }
+ public List Documentation { get; } = new();
public bool IsAnonymous { get; set; }
- public GeneratorConfiguration Configuration { get; private set; }
public virtual bool IsSubtype => false;
- protected TypeModel(GeneratorConfiguration configuration)
- {
- Configuration = configuration;
- Documentation = new List();
- }
+ protected TypeModel(GeneratorConfiguration configuration) : base(configuration) { }
public virtual CodeTypeDeclaration Generate()
{
var typeDeclaration = new CodeTypeDeclaration { Name = Name };
- typeDeclaration.Comments.AddRange(DocumentationModel.GetComments(Documentation, Configuration).ToArray());
+ typeDeclaration.Comments.AddRange(GetComments(Documentation).ToArray());
- DocumentationModel.AddDescription(typeDeclaration.CustomAttributes, Documentation, Configuration);
+ AddDescription(typeDeclaration.CustomAttributes, Documentation);
- var generatedAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(GeneratedCodeAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(Configuration.Version.Title)),
- new CodeAttributeArgument(new CodePrimitiveExpression(Configuration.CreateGeneratedCodeAttributeVersion ? Configuration.Version.Version : "")));
+ var generatedAttribute = AttributeDecl(
+ new(new CodePrimitiveExpression(Configuration.Version.Title)),
+ new(new CodePrimitiveExpression(Configuration.CreateGeneratedCodeAttributeVersion ? Configuration.Version.Version : "")));
typeDeclaration.CustomAttributes.Add(generatedAttribute);
return typeDeclaration;
@@ -143,29 +91,24 @@ public virtual CodeTypeDeclaration Generate()
protected void GenerateTypeAttribute(CodeTypeDeclaration typeDeclaration)
{
- if (XmlSchemaName != null)
- {
- var typeAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlTypeAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)),
- new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(XmlSchemaName.Namespace)));
- if (IsAnonymous && !IsSubtype)
- {
- // don't generate AnonymousType if it's derived class, otherwise XmlSerializer will
- // complain with "InvalidOperationException: Cannot include anonymous type '...'"
- typeAttribute.Arguments.Add(new CodeAttributeArgument("AnonymousType", new CodePrimitiveExpression(true)));
- }
- typeDeclaration.CustomAttributes.Add(typeAttribute);
- }
+ if (XmlSchemaName == null) return;
+
+ var typeAttribute = AttributeDecl(
+ new(new CodePrimitiveExpression(XmlSchemaName.Name)),
+ new(nameof(XmlRootAttribute.Namespace), new CodePrimitiveExpression(XmlSchemaName.Namespace)));
+
+ // don't generate AnonymousType if it's derived class, otherwise XmlSerializer will
+ // complain with "InvalidOperationException: Cannot include anonymous type '...'"
+ if (IsAnonymous && !IsSubtype)
+ typeAttribute.Arguments.Add(new("AnonymousType", new CodePrimitiveExpression(true)));
+
+ typeDeclaration.CustomAttributes.Add(typeAttribute);
}
protected void GenerateSerializableAttribute(CodeTypeDeclaration typeDeclaration)
{
if (Configuration.GenerateSerializableAttribute)
- {
- var serializableAttribute =
- new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(SerializableAttribute), Configuration));
- typeDeclaration.CustomAttributes.Add(serializableAttribute);
- }
+ typeDeclaration.CustomAttributes.Add(AttributeDecl());
}
public virtual CodeTypeReference GetReferenceFor(NamespaceModel referencingNamespace, bool collection = false, bool forInit = false, bool attribute = false)
@@ -179,21 +122,20 @@ public virtual CodeTypeReference GetReferenceFor(NamespaceModel referencingNames
}
else if ((referencingNamespace ?? Namespace).IsAmbiguous)
{
- name = string.Format("global::{0}.{1}", Namespace.Name, Name);
+ name = $"global::{Namespace.Name}.{Name}";
referencingOptions = CodeTypeReferenceOptions.GenericTypeParameter;
}
else
{
- name = string.Format("{0}.{1}", Namespace.Name, Name);
+ name = $"{Namespace.Name}.{Name}";
}
if (collection)
{
name = forInit ? SimpleModel.GetCollectionImplementationName(name, Configuration) : SimpleModel.GetCollectionDefinitionName(name, Configuration);
- if (Configuration.CollectionType == typeof(System.Array))
- referencingOptions = CodeTypeReferenceOptions.GenericTypeParameter;
- else
- referencingOptions = Configuration.CodeTypeReferenceOptions;
+ referencingOptions = Configuration.CollectionType == typeof(Array)
+ ? CodeTypeReferenceOptions.GenericTypeParameter
+ : Configuration.CodeTypeReferenceOptions;
}
return new CodeTypeReference(name, referencingOptions);
@@ -227,7 +169,6 @@ public override CodeTypeDeclaration Generate()
interfaceDeclaration.TypeAttributes = (interfaceDeclaration.TypeAttributes & ~System.Reflection.TypeAttributes.VisibilityMask) | System.Reflection.TypeAttributes.NestedAssembly;
}
-
foreach (var property in Properties)
property.AddInterfaceMembersTo(interfaceDeclaration);
@@ -250,23 +191,23 @@ public IEnumerable AllDerivedReferenceTypes(List(),
Attributes = MemberAttributes.Public,
};
classDeclaration.Members.Add(propertyChangedEvent);
@@ -347,16 +288,16 @@ public override CodeTypeDeclaration Generate()
Configuration.MemberVisitor(propertyChangedEvent, propertyChangedModel);
+ var param = new CodeParameterDeclarationExpression(typeof(string), "propertyName");
+ var threadSafeDelegateInvokeExpression = new CodeSnippetExpression($"{propertyChangedEvent.Name}?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs({param.Name}))");
var onPropChangedMethod = new CodeMemberMethod
{
- Name = "OnPropertyChanged",
+ Name = OnPropertyChanged,
Attributes = MemberAttributes.Family,
+ Parameters = { param },
+ Statements = { threadSafeDelegateInvokeExpression }
};
- var param = new CodeParameterDeclarationExpression(typeof(string), "propertyName");
- onPropChangedMethod.Parameters.Add(param);
- var threadSafeDelegateInvokeExpression = new CodeSnippetExpression($"{propertyChangedEvent.Name}?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs({param.Name}))");
- onPropChangedMethod.Statements.Add(threadSafeDelegateInvokeExpression);
classDeclaration.Members.Add(onPropChangedMethod);
}
@@ -387,31 +328,26 @@ public override CodeTypeDeclaration Generate()
else
{
// hack to generate automatic property
- member.Name += " { get; set; }";
+ member.Name += GetSet;
}
- var docs = new List { new DocumentationModel { Language = "en", Text = "Gets or sets the text value." },
- new DocumentationModel { Language = "de", Text = "Ruft den Text ab oder legt diesen fest." } };
+ var docs = new List {
+ new() { Language = English, Text = "Gets or sets the text value." },
+ new() { Language = German, Text = "Ruft den Text ab oder legt diesen fest." }
+ };
- var attribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlTextAttribute), Configuration));
+ var attribute = AttributeDecl();
if (BaseClass is SimpleModel simpleModel)
{
- docs.AddRange(simpleModel.Restrictions.Select(r => new DocumentationModel { Language = "en", Text = r.Description }));
+ docs.AddRange(simpleModel.Restrictions.Select(r => new DocumentationModel { Language = English, Text = r.Description }));
member.CustomAttributes.AddRange(simpleModel.GetRestrictionAttributes().ToArray());
- if (simpleModel.XmlSchemaType.Datatype.IsDataTypeAttributeAllowed() ?? simpleModel.UseDataTypeAttribute)
- {
- var name = BaseClass.GetQualifiedName();
- if (name.Namespace == XmlSchema.Namespace)
- {
- var dataType = new CodeAttributeArgument("DataType", new CodePrimitiveExpression(name.Name));
- attribute.Arguments.Add(dataType);
- }
- }
+ if (BaseClass.GetQualifiedName() is { Namespace: XmlSchema.Namespace, Name: var name } && (simpleModel.XmlSchemaType.Datatype.IsDataTypeAttributeAllowed() ?? simpleModel.UseDataTypeAttribute))
+ attribute.Arguments.Add(new CodeAttributeArgument(nameof(XmlTextAttribute.DataType), new CodePrimitiveExpression(name)));
}
- member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray());
+ member.Comments.AddRange(GetComments(docs).ToArray());
member.CustomAttributes.Add(attribute);
classDeclaration.Members.Add(member);
@@ -429,14 +365,14 @@ public override CodeTypeDeclaration Generate()
if (Configuration.EnableDataBinding)
{
- classDeclaration.BaseTypes.Add(CodeUtilities.CreateTypeReference(typeof(INotifyPropertyChanged), Configuration));
+ classDeclaration.BaseTypes.Add(TypeRef());
}
if (Configuration.EntityFramework && BaseClass is not ClassModel)
{
// generate key
- var keyProperty = Properties.FirstOrDefault(p => p.Name.ToLowerInvariant() == "id")
- ?? Properties.FirstOrDefault(p => p.Name.ToLowerInvariant() == (Name.ToLowerInvariant() + "id"));
+ var keyProperty = Properties.Find(p => string.Equals(p.Name, "id", StringComparison.InvariantCultureIgnoreCase))
+ ?? Properties.Find(p => p.Name.ToLowerInvariant() == Name.ToLowerInvariant() + "id");
if (keyProperty == null)
{
@@ -445,8 +381,10 @@ public override CodeTypeDeclaration Generate()
Name = "Id",
Type = new SimpleModel(Configuration) { ValueType = typeof(long) },
OwningType = this,
- Documentation = { new DocumentationModel { Language = "en", Text = "Gets or sets a value uniquely identifying this entity." },
- new DocumentationModel { Language = "de", Text = "Ruft einen Wert ab, der diese Entität eindeutig identifiziert, oder legt diesen fest." } }
+ Documentation = {
+ new() { Language = English, Text = "Gets or sets a value uniquely identifying this entity." },
+ new() { Language = German, Text = "Ruft einen Wert ab, der diese Entität eindeutig identifiziert, oder legt diesen fest." }
+ }
};
Properties.Insert(0, keyProperty);
}
@@ -454,20 +392,18 @@ public override CodeTypeDeclaration Generate()
keyProperty.IsKey = true;
}
- foreach (var property in Properties.GroupBy(x => x.Name).Select(g => g.Select((p, i) => (Property: p, Index: i)).ToList()))
+ var properties = Properties.GroupBy(x => x.Name).SelectMany(g => g.Select((p, i) => (Property: p, Index: i)).ToList());
+ foreach (var (Property, Index) in properties)
{
- foreach (var p in property)
+ if (Index > 0)
{
- if (p.Index > 0)
- {
- p.Property.Name += $"_{p.Index + 1}";
-
- if (property.Any(q => p.Property.XmlSchemaName == q.Property.XmlSchemaName && q.Index < p.Index))
- continue;
- }
+ Property.Name += $"_{Index + 1}";
- p.Property.AddMembersTo(classDeclaration, Configuration.EnableDataBinding);
+ if (properties.Any(q => Property.XmlSchemaName == q.Property.XmlSchemaName && q.Index < Index))
+ continue;
}
+
+ Property.AddMembersTo(classDeclaration, Configuration.EnableDataBinding);
}
if (IsMixed && (BaseClass == null || (BaseClass is ClassModel && !AllBaseClasses.Any(b => b.IsMixed))))
@@ -481,9 +417,9 @@ public override CodeTypeDeclaration Generate()
}
var text = new CodeMemberField(typeof(string[]), propName);
// hack to generate automatic property
- text.Name += " { get; set; }";
+ text.Name += GetSet;
text.Attributes = MemberAttributes.Public;
- var xmlTextAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlTextAttribute), Configuration));
+ var xmlTextAttribute = AttributeDecl();
text.CustomAttributes.Add(xmlTextAttribute);
classDeclaration.Members.Add(text);
@@ -497,32 +433,25 @@ public override CodeTypeDeclaration Generate()
Configuration.MemberVisitor(text, textPropertyModel);
}
+ var customAttributes = classDeclaration.CustomAttributes;
+
if (Configuration.GenerateDebuggerStepThroughAttribute)
- classDeclaration.CustomAttributes.Add(
- new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(DebuggerStepThroughAttribute), Configuration)));
+ customAttributes.Add(AttributeDecl());
if (Configuration.GenerateDesignerCategoryAttribute)
- {
- classDeclaration.CustomAttributes.Add(
- new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(DesignerCategoryAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression("code"))));
- }
+ customAttributes.Add(AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression("code"))));
if (RootElementName != null)
{
- var rootAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlRootAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(RootElementName.Name)),
- new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(RootElementName.Namespace)));
- classDeclaration.CustomAttributes.Add(rootAttribute);
+ var rootAttribute = AttributeDecl(
+ new(new CodePrimitiveExpression(RootElementName.Name)),
+ new(nameof(XmlRootAttribute.Namespace), new CodePrimitiveExpression(RootElementName.Namespace)));
+ customAttributes.Add(rootAttribute);
}
var derivedTypes = GetAllDerivedTypes();
foreach (var derivedType in derivedTypes.OrderBy(t => t.Name))
- {
- var includeAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlIncludeAttribute), Configuration),
- new CodeAttributeArgument(new CodeTypeOfExpression(derivedType.GetReferenceFor(Namespace))));
- classDeclaration.CustomAttributes.Add(includeAttribute);
- }
+ customAttributes.Add(AttributeDecl(new CodeAttributeArgument(new CodeTypeOfExpression(derivedType.GetReferenceFor(Namespace)))));
classDeclaration.BaseTypes.AddRange(Interfaces.Select(i => i.GetReferenceFor(Namespace)).ToArray());
@@ -560,8 +489,7 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
reference = writer.ToString();
}
- var dv = new CodeSnippetExpression($"new { reference } {{ { Configuration.TextValuePropertyName } = { val } }};");
- return dv;
+ return new CodeSnippetExpression($"new {reference} {{ {Configuration.TextValuePropertyName} = {val} }};");
}
return base.GetDefaultValueFor(defaultString, attribute);
@@ -594,8 +522,12 @@ public void AddInterfaces(IEnumerable interfaces)
}
[DebuggerDisplay("{Name}")]
- public class PropertyModel
+ public class PropertyModel : GeneratorModel
{
+ private const string Value = nameof(Value);
+ private const string Specified = nameof(Specified);
+ private const string Namespace = nameof(XmlRootAttribute.Namespace);
+
public TypeModel OwningType { get; set; }
public string Name { get; set; }
public string OriginalPropertyName { get; set; }
@@ -608,7 +540,7 @@ public class PropertyModel
public string FixedValue { get; set; }
public XmlSchemaForm Form { get; set; }
public string XmlNamespace { get; set; }
- public List Documentation { get; private set; }
+ public List Documentation { get; }
public bool IsDeprecated { get; set; }
public XmlQualifiedName XmlSchemaName { get; set; }
public bool IsAny { get; set; }
@@ -617,215 +549,103 @@ public class PropertyModel
public XmlSchemaParticle XmlParticle { get; set; }
public XmlSchemaObject XmlParent { get; set; }
public Particle Particle { get; set; }
- public GeneratorConfiguration Configuration { get; private set; }
public List Substitutes { get; set; }
- public PropertyModel(GeneratorConfiguration configuration)
+ public PropertyModel(GeneratorConfiguration configuration) : base(configuration)
{
- Configuration = configuration;
Documentation = new List();
Substitutes = new List();
}
internal static string GetAccessors(string memberName, string backingFieldName, PropertyValueTypeCode typeCode, bool privateSetter, bool withDataBinding = true)
{
- if (withDataBinding)
- {
- switch (typeCode)
- {
- case PropertyValueTypeCode.ValueType:
- return CodeUtilities.NormalizeNewlines(string.Format(@"
- {{
- get
- {{
- return {0};
- }}
- {2}set
- {{
- if (!{0}.Equals(value))
- {{
- {0} = value;
- OnPropertyChanged(nameof({1}));
- }}
- }}
- }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)));
- case PropertyValueTypeCode.Other:
- return CodeUtilities.NormalizeNewlines(string.Format(@"
- {{
- get
- {{
- return {0};
- }}
- {2}set
- {{
- if ({0} == value)
- return;
- if ({0} == null || value == null || !{0}.Equals(value))
- {{
- {0} = value;
- OnPropertyChanged(nameof({1}));
- }}
- }}
- }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)));
- case PropertyValueTypeCode.Array:
- return CodeUtilities.NormalizeNewlines(string.Format(@"
- {{
- get
- {{
- return {0};
- }}
- {2}set
- {{
- if ({0} == value)
- return;
- if ({0} == null || value == null || !{0}.SequenceEqual(value))
- {{
- {0} = value;
- OnPropertyChanged(nameof({1}));
- }}
- }}
- }}", backingFieldName, memberName, (privateSetter ? "private " : string.Empty)));
- }
- }
+ string assign = $@"
+ {backingFieldName} = value;";
- if (privateSetter)
- {
- return CodeUtilities.NormalizeNewlines(string.Format(@"
+ return CodeUtilities.NormalizeNewlines($@"
{{
get
{{
- return this.{0};
+ return {backingFieldName};
}}
- private set
- {{
- this.{0} = value;
+ {(privateSetter ? "private " : string.Empty)}set
+ {{{(typeCode, withDataBinding) switch
+ {
+ (PropertyValueTypeCode.ValueType, true) => $@"
+ if (!{backingFieldName}.Equals(value))
+ {{{assign}
+ OnPropertyChanged(nameof({memberName}));
+ }}",
+ (PropertyValueTypeCode.Other or PropertyValueTypeCode.Array, true) => $@"
+ if ({backingFieldName} == value)
+ return;
+ if ({backingFieldName} == null || value == null || !{backingFieldName}.{(typeCode is PropertyValueTypeCode.Other ? EqualsMethod : nameof(Enumerable.SequenceEqual))}(value))
+ {{{assign}
+ OnPropertyChanged(nameof({memberName}));
+ }}",
+ _ => assign,
}}
- }}", backingFieldName));
- }
- else
- {
- return CodeUtilities.NormalizeNewlines(string.Format(@"
- {{
- get
- {{
- return this.{0};
}}
- set
- {{
- this.{0} = value;
- }}
- }}", backingFieldName));
- }
+ }}");
}
- private ClassModel TypeClassModel
- {
- get { return Type as ClassModel; }
- }
+ private ClassModel TypeClassModel => Type as ClassModel;
///
/// A property is an array if it is a sequence containing a single element with maxOccurs > 1.
///
- public bool IsArray
- {
- get
- {
- return Configuration.UseArrayItemAttribute
+ public bool IsArray => Configuration.UseArrayItemAttribute
&& !IsCollection && !IsAttribute && !IsList && TypeClassModel != null
&& TypeClassModel.BaseClass == null
&& TypeClassModel.Properties.Count == 1
&& !TypeClassModel.Properties[0].IsAttribute && !TypeClassModel.Properties[0].IsAny
&& TypeClassModel.Properties[0].IsCollection;
- }
- }
- private TypeModel PropertyType
- {
- get { return !IsArray ? Type : TypeClassModel.Properties[0].Type; }
- }
+ private TypeModel PropertyType => !IsArray ? Type : TypeClassModel.Properties[0].Type;
- private bool IsNullableValueType
- {
- get
- {
- return DefaultValue == null
+ private bool IsNullableValueType => DefaultValue == null
&& IsNullable && !(IsCollection || IsArray) && !IsList
&& ((PropertyType is EnumModel) || (PropertyType is SimpleModel model && model.ValueType.IsValueType));
- }
- }
- private bool IsNullableReferenceType
- {
- get
- {
- return DefaultValue == null
- && IsNullable && (IsCollection || IsArray || IsList || PropertyType is ClassModel || PropertyType is SimpleModel model && !model.ValueType.IsValueType);
- }
- }
+ private bool IsNullableReferenceType => DefaultValue == null
+ && IsNullable && (IsCollection || IsArray || IsList || PropertyType is ClassModel || (PropertyType is SimpleModel model && !model.ValueType.IsValueType));
- private bool IsNillableValueType
- {
- get
- {
- return IsNillable
+ private bool IsNillableValueType => IsNillable
&& !(IsCollection || IsArray)
&& ((PropertyType is EnumModel) || (PropertyType is SimpleModel model && model.ValueType.IsValueType));
- }
- }
- private bool IsList
- {
- get
- {
- return Type.XmlSchemaType?.Datatype?.Variety == XmlSchemaDatatypeVariety.List;
- }
- }
+ private bool IsList => Type.XmlSchemaType?.Datatype?.Variety == XmlSchemaDatatypeVariety.List;
- private bool IsPrivateSetter
- {
- get
- {
- return Configuration.CollectionSettersMode == CollectionSettersMode.Private
+ private bool IsPrivateSetter => Configuration.CollectionSettersMode == CollectionSettersMode.Private
&& (IsCollection || IsArray || (IsList && IsAttribute));
- }
- }
- private CodeTypeReference TypeReference
- {
- get
- {
- return PropertyType.GetReferenceFor(OwningType.Namespace,
+ private CodeTypeReference TypeReference => PropertyType.GetReferenceFor(OwningType.Namespace,
collection: IsCollection || IsArray || (IsList && IsAttribute),
attribute: IsAttribute);
- }
- }
private void AddDocs(CodeTypeMember member)
{
var docs = new List(Documentation);
- DocumentationModel.AddDescription(member.CustomAttributes, docs, Configuration);
+ AddDescription(member.CustomAttributes, docs);
if (PropertyType is SimpleModel simpleType)
{
docs.AddRange(simpleType.Documentation);
- docs.AddRange(simpleType.Restrictions.Select(r => new DocumentationModel { Language = "en", Text = r.Description }));
+ docs.AddRange(simpleType.Restrictions.Select(r => new DocumentationModel { Language = English, Text = r.Description }));
member.CustomAttributes.AddRange(simpleType.GetRestrictionAttributes().ToArray());
}
- member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray());
+ member.Comments.AddRange(GetComments(docs).ToArray());
}
private CodeAttributeDeclaration CreateDefaultValueAttribute(CodeTypeReference typeReference, CodeExpression defaultValueExpression)
{
- var defaultValueAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(DefaultValueAttribute), Configuration));
- if (typeReference.BaseType == "System.Decimal")
- {
- defaultValueAttribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(typeof(decimal))));
- defaultValueAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(DefaultValue)));
- }
- else
- defaultValueAttribute.Arguments.Add(new CodeAttributeArgument(defaultValueExpression));
+ var defaultValueAttribute = AttributeDecl();
+
+ defaultValueAttribute.Arguments.AddRange(typeReference.BaseType == typeof(decimal).FullName
+ ? new CodeAttributeArgument[] { new(new CodeTypeOfExpression(typeof(decimal))), new(new CodePrimitiveExpression(DefaultValue)) }
+ : new CodeAttributeArgument[] { new(defaultValueExpression) });
return defaultValueAttribute;
}
@@ -840,11 +660,7 @@ public void AddInterfaceMembersTo(CodeTypeDeclaration typeDeclaration)
var typeReference = TypeReference;
if (isNullableValueType && Configuration.GenerateNullables)
- {
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
- typeReference = nullableType;
- }
+ typeReference = NullableTypeRef(typeReference);
member = new CodeMemberProperty
{
@@ -858,8 +674,7 @@ public void AddInterfaceMembersTo(CodeTypeDeclaration typeDeclaration)
{
var defaultValueExpression = propertyType.GetDefaultValueFor(DefaultValue, IsAttribute);
- if ((defaultValueExpression is CodePrimitiveExpression) || (defaultValueExpression is CodeFieldReferenceExpression)
- && !CodeUtilities.IsXmlLangOrSpace(XmlSchemaName))
+ if ((defaultValueExpression is CodePrimitiveExpression or CodeFieldReferenceExpression) && !CodeUtilities.IsXmlLangOrSpace(XmlSchemaName))
{
var defaultValueAttribute = CreateDefaultValueAttribute(typeReference, defaultValueExpression);
member.CustomAttributes.Add(defaultValueAttribute);
@@ -874,7 +689,8 @@ public void AddInterfaceMembersTo(CodeTypeDeclaration typeDeclaration)
// ReSharper disable once FunctionComplexityOverflow
public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBinding)
{
- CodeTypeMember member;
+ // Note: We use CodeMemberField because CodeMemberProperty doesn't allow for private set
+ var member = new CodeMemberField() { Name = Name };
var typeClassModel = TypeClassModel;
var isArray = IsArray;
@@ -884,101 +700,60 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
var isPrivateSetter = IsPrivateSetter;
var typeReference = TypeReference;
- var requiresBackingField = withDataBinding || DefaultValue != null || IsCollection || isArray;
- CodeMemberField backingField;
+ CodeAttributeDeclaration ignoreAttribute = new(TypeRef());
+ CodeAttributeDeclaration notMappedAttribute = new(CodeUtilities.CreateTypeReference(Attributes.NotMapped, Configuration));
- if (IsNillableValueType)
- {
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
- backingField = new CodeMemberField(nullableType, OwningType.GetUniqueFieldName(this));
- }
- else
- {
- backingField = new CodeMemberField(typeReference, OwningType.GetUniqueFieldName(this))
- {
- Attributes = MemberAttributes.Private
- };
- }
-
- var ignoreAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlIgnoreAttribute), Configuration));
- var notMappedAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations.Schema", "NotMappedAttribute", Configuration));
- backingField.CustomAttributes.Add(ignoreAttribute);
-
- if (requiresBackingField)
+ CodeMemberField backingField = null;
+ if (withDataBinding || DefaultValue != null || IsCollection || isArray)
{
+ backingField = IsNillableValueType
+ ? new CodeMemberField(NullableTypeRef(typeReference), OwningType.GetUniqueFieldName(this))
+ : new CodeMemberField(typeReference, OwningType.GetUniqueFieldName(this)) { Attributes = MemberAttributes.Private };
+ backingField.CustomAttributes.Add(ignoreAttribute);
typeDeclaration.Members.Add(backingField);
}
if (DefaultValue == null || ((IsCollection || isArray || (IsList && IsAttribute)) && IsNullable))
{
- var propertyName = Name;
-
if (isNullableValueType && Configuration.GenerateNullables && !(Configuration.UseShouldSerializePattern && !IsAttribute))
- {
- propertyName += "Value";
- }
+ member.Name += Value;
if (IsNillableValueType)
{
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
- member = new CodeMemberField(nullableType, propertyName);
+ member.Type = NullableTypeRef(typeReference);
}
else if (isNullableValueType && !IsAttribute && Configuration.UseShouldSerializePattern)
{
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
- member = new CodeMemberField(nullableType, propertyName);
+ member.Type = NullableTypeRef(typeReference);
typeDeclaration.Members.Add(new CodeMemberMethod
{
Attributes = MemberAttributes.Public,
- Name = "ShouldSerialize" + propertyName,
+ Name = "ShouldSerialize" + member.Name,
ReturnType = new CodeTypeReference(typeof(bool)),
- Statements =
- {
- new CodeSnippetExpression($"return {propertyName}.HasValue")
- }
+ Statements = { new CodeSnippetExpression($"return {member.Name}.{HasValue}") }
});
}
else
- member = new CodeMemberField(typeReference, propertyName);
-
- if (requiresBackingField)
{
- member.Name += GetAccessors(member.Name, backingField.Name,
- IsCollection || isArray ? PropertyValueTypeCode.Array : propertyType.GetPropertyValueTypeCode(),
- isPrivateSetter, withDataBinding);
- }
- else
- {
- // hack to generate automatic property
- member.Name += isPrivateSetter ? " { get; private set; }" : " { get; set; }";
+ member.Type = typeReference;
}
+
+ member.Name += backingField != null
+ ? GetAccessors(member.Name, backingField.Name, IsCollection || isArray ? PropertyValueTypeCode.Array : propertyType.GetPropertyValueTypeCode(), isPrivateSetter, withDataBinding)
+ : $" {{ get; {(isPrivateSetter ? "private " : string.Empty)}set; }}"; // hack to generate automatic property
}
else
{
var defaultValueExpression = propertyType.GetDefaultValueFor(DefaultValue, IsAttribute);
backingField.InitExpression = defaultValueExpression;
- if (IsNillableValueType)
- {
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
- member = new CodeMemberField(nullableType, Name);
- }
- else
- member = new CodeMemberField(typeReference, Name);
+ member.Type = IsNillableValueType ? NullableTypeRef(typeReference) : typeReference;
member.Name += GetAccessors(member.Name, backingField.Name, propertyType.GetPropertyValueTypeCode(), false, withDataBinding);
- if (IsNullable && ((defaultValueExpression is CodePrimitiveExpression) || (defaultValueExpression is CodeFieldReferenceExpression))
- && !CodeUtilities.IsXmlLangOrSpace(XmlSchemaName))
- {
- var defaultValueAttribute = CreateDefaultValueAttribute(typeReference, defaultValueExpression);
- member.CustomAttributes.Add(defaultValueAttribute);
- }
+ if (IsNullable && (defaultValueExpression is CodePrimitiveExpression or CodeFieldReferenceExpression) && !CodeUtilities.IsXmlLangOrSpace(XmlSchemaName))
+ member.CustomAttributes.Add(CreateDefaultValueAttribute(typeReference, defaultValueExpression));
}
member.Attributes = MemberAttributes.Public;
@@ -988,7 +763,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
if (!IsNullable && Configuration.DataAnnotationMode != DataAnnotationMode.None)
{
- var requiredAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "RequiredAttribute", Configuration));
+ var requiredAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(Attributes.Required, Configuration));
member.CustomAttributes.Add(requiredAttribute);
}
@@ -1008,34 +783,31 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
generateSpecifiedProperty = false;
}
- var specifiedName = generateNullablesProperty ? Name + "Value" : Name;
+ var specifiedName = generateNullablesProperty ? Name + Value : Name;
CodeMemberField specifiedMember = null;
if (generateSpecifiedProperty)
{
- specifiedMember = new CodeMemberField(typeof(bool), specifiedName + "Specified { get; set; }");
+ specifiedMember = new CodeMemberField(typeof(bool), specifiedName + Specified + GetSet);
specifiedMember.CustomAttributes.Add(ignoreAttribute);
if (Configuration.EntityFramework && generateNullablesProperty) { specifiedMember.CustomAttributes.Add(notMappedAttribute); }
specifiedMember.Attributes = MemberAttributes.Public;
- var specifiedDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format("Gets or sets a value indicating whether the {0} property is specified.", Name) },
- new DocumentationModel { Language = "de", Text = string.Format("Ruft einen Wert ab, der angibt, ob die {0}-Eigenschaft spezifiziert ist, oder legt diesen fest.", Name) } };
- specifiedMember.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs, Configuration).ToArray());
+ var specifiedDocs = new DocumentationModel[] {
+ new() { Language = English, Text = $"Gets or sets a value indicating whether the {Name} property is specified." },
+ new() { Language = German, Text = $"Ruft einen Wert ab, der angibt, ob die {Name}-Eigenschaft spezifiziert ist, oder legt diesen fest." }
+ };
+ specifiedMember.Comments.AddRange(GetComments(specifiedDocs).ToArray());
typeDeclaration.Members.Add(specifiedMember);
- var specifiedMemberPropertyModel = new PropertyModel(Configuration)
- {
- Name = specifiedName + "Specified"
- };
+ var specifiedMemberPropertyModel = new PropertyModel(Configuration) { Name = specifiedName + Specified };
Configuration.MemberVisitor(specifiedMember, specifiedMemberPropertyModel);
}
if (generateNullablesProperty)
{
- var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
- nullableType.TypeArguments.Add(typeReference);
var nullableMember = new CodeMemberProperty
{
- Type = nullableType,
+ Type = NullableTypeRef(typeReference),
Name = Name,
HasSet = true,
HasGet = true,
@@ -1044,16 +816,16 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
nullableMember.CustomAttributes.Add(ignoreAttribute);
nullableMember.Comments.AddRange(member.Comments);
- var specifiedExpression = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), specifiedName + "Specified");
- var valueExpression = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), Name + "Value");
+ var specifiedExpression = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), specifiedName + Specified);
+ var valueExpression = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), Name + Value);
var conditionStatement = new CodeConditionStatement(specifiedExpression,
new CodeStatement[] { new CodeMethodReturnStatement(valueExpression) },
new CodeStatement[] { new CodeMethodReturnStatement(new CodePrimitiveExpression(null)) });
nullableMember.GetStatements.Add(conditionStatement);
- var getValueOrDefaultExpression = new CodeMethodInvokeExpression(new CodePropertySetValueReferenceExpression(), "GetValueOrDefault");
+ var getValueOrDefaultExpression = new CodeMethodInvokeExpression(new CodePropertySetValueReferenceExpression(), nameof(Nullable.GetValueOrDefault));
var setValueStatement = new CodeAssignStatement(valueExpression, getValueOrDefaultExpression);
- var hasValueExpression = new CodePropertyReferenceExpression(new CodePropertySetValueReferenceExpression(), "HasValue");
+ var hasValueExpression = new CodePropertyReferenceExpression(new CodePropertySetValueReferenceExpression(), HasValue);
var setSpecifiedStatement = new CodeAssignStatement(specifiedExpression, hasValueExpression);
var statements = new List();
@@ -1062,20 +834,20 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
var ifNotEquals = new CodeConditionStatement(
new CodeBinaryOperatorExpression(
new CodeBinaryOperatorExpression(
- new CodeMethodInvokeExpression(valueExpression, "Equals", getValueOrDefaultExpression),
+ new CodeMethodInvokeExpression(valueExpression, EqualsMethod, getValueOrDefaultExpression),
CodeBinaryOperatorType.ValueEquality,
new CodePrimitiveExpression(false)
),
CodeBinaryOperatorType.BooleanOr,
new CodeBinaryOperatorExpression(
- new CodeMethodInvokeExpression(specifiedExpression, "Equals", hasValueExpression),
+ new CodeMethodInvokeExpression(specifiedExpression, EqualsMethod, hasValueExpression),
CodeBinaryOperatorType.ValueEquality,
new CodePrimitiveExpression(false)
)
),
setValueStatement,
setSpecifiedStatement,
- new CodeExpressionStatement(new CodeMethodInvokeExpression(null, "OnPropertyChanged",
+ new CodeExpressionStatement(new CodeMethodInvokeExpression(null, OnPropertyChanged,
new CodePrimitiveExpression(Name)))
);
statements.Add(ifNotEquals);
@@ -1090,8 +862,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
typeDeclaration.Members.Add(nullableMember);
- var editorBrowsableAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(EditorBrowsableAttribute), Configuration));
- editorBrowsableAttribute.Arguments.Add(new CodeAttributeArgument(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CodeUtilities.CreateTypeReference(typeof(EditorBrowsableState), Configuration)), "Never")));
+ var editorBrowsableAttribute = AttributeDecl();
+ editorBrowsableAttribute.Arguments.Add(new(new CodeFieldReferenceExpression(TypeRefExpr(), nameof(EditorBrowsableState.Never))));
specifiedMember?.CustomAttributes.Add(editorBrowsableAttribute);
member.CustomAttributes.Add(editorBrowsableAttribute);
if (Configuration.EntityFramework) { member.CustomAttributes.Add(notMappedAttribute); }
@@ -1103,8 +875,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
{
var specifiedProperty = new CodeMemberProperty
{
- Type = CodeUtilities.CreateTypeReference(typeof(bool), Configuration),
- Name = Name + "Specified",
+ Type = TypeRef(),
+ Name = Name + Specified,
HasSet = false,
HasGet = true,
};
@@ -1114,7 +886,7 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
var listReference = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), Name);
var collectionType = Configuration.CollectionImplementationType ?? Configuration.CollectionType;
- var countProperty = collectionType == typeof(System.Array) ? "Length" : "Count";
+ var countProperty = collectionType == typeof(Array) ? nameof(Array.Length) : nameof(List.Count);
var countReference = new CodePropertyReferenceExpression(listReference, countProperty);
var notZeroExpression = new CodeBinaryOperatorExpression(countReference, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(0));
if (Configuration.CollectionSettersMode is CollectionSettersMode.PublicWithoutConstructorInitialization or CollectionSettersMode.Public)
@@ -1125,19 +897,21 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
var returnStatement = new CodeMethodReturnStatement(notZeroExpression);
specifiedProperty.GetStatements.Add(returnStatement);
- var specifiedDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format("Gets a value indicating whether the {0} collection is empty.", Name) },
- new DocumentationModel { Language = "de", Text = string.Format("Ruft einen Wert ab, der angibt, ob die {0}-Collection leer ist.", Name) } };
- specifiedProperty.Comments.AddRange(DocumentationModel.GetComments(specifiedDocs, Configuration).ToArray());
+ var specifiedDocs = new DocumentationModel[] {
+ new() { Language = English, Text = $"Gets a value indicating whether the {Name} collection is empty." },
+ new() { Language = German, Text = $"Ruft einen Wert ab, der angibt, ob die {Name}-Collection leer ist." }
+ };
+ specifiedProperty.Comments.AddRange(GetComments(specifiedDocs).ToArray());
Configuration.MemberVisitor(specifiedProperty, this);
typeDeclaration.Members.Add(specifiedProperty);
}
- if (isNullableReferenceType && Configuration.EnableNullableReferenceAttributes)
+ if (!IsCollection && isNullableReferenceType && Configuration.EnableNullableReferenceAttributes)
{
- member.CustomAttributes.Add(new CodeAttributeDeclaration("System.Diagnostics.CodeAnalysis.AllowNullAttribute"));
- member.CustomAttributes.Add(new CodeAttributeDeclaration("System.Diagnostics.CodeAnalysis.MaybeNullAttribute"));
+ member.CustomAttributes.Add(new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(Attributes.AllowNull, Configuration)));
+ member.CustomAttributes.Add(new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(Attributes.MaybeNull, Configuration)));
}
var attributes = GetAttributes(isArray).ToArray();
@@ -1151,23 +925,25 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
if (constructor == null)
{
constructor = new CodeConstructor { Attributes = MemberAttributes.Public | MemberAttributes.Final };
- var constructorDocs = new[] { new DocumentationModel { Language = "en", Text = string.Format(@"Initializes a new instance of the class.", typeDeclaration.Name) },
- new DocumentationModel { Language = "de", Text = string.Format(@"Initialisiert eine neue Instanz der Klasse.", typeDeclaration.Name) } };
- constructor.Comments.AddRange(DocumentationModel.GetComments(constructorDocs, Configuration).ToArray());
+ var constructorDocs = new DocumentationModel[] {
+ new() { Language = English, Text = $@"Initializes a new instance of the class." },
+ new() { Language = German, Text = $@"Initialisiert eine neue Instanz der Klasse." }
+ };
+ constructor.Comments.AddRange(GetComments(constructorDocs).ToArray());
typeDeclaration.Members.Add(constructor);
}
- var listReference = requiresBackingField ? (CodeExpression)new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name) :
- new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), Name);
+ CodeExpression listReference = backingField != null
+ ? new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name)
+ : new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), Name);
var collectionType = Configuration.CollectionImplementationType ?? Configuration.CollectionType;
CodeExpression initExpression;
- if (collectionType == typeof(System.Array))
+ if (collectionType == typeof(Array))
{
var initTypeReference = propertyType.GetReferenceFor(OwningType.Namespace, collection: false, forInit: true, attribute: IsAttribute);
- var arrayReference = CodeUtilities.CreateTypeReference(typeof(System.Array), Configuration);
- initExpression = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(arrayReference), "Empty", initTypeReference));
+ initExpression = new CodeMethodInvokeExpression(new(TypeRefExpr(), nameof(Array.Empty), initTypeReference));
}
else
{
@@ -1181,29 +957,24 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi
if (isArray)
{
var arrayItemProperty = typeClassModel.Properties[0];
- var propertyAttributes = arrayItemProperty.GetAttributes(false, OwningType).ToList();
+
// HACK: repackage as ArrayItemAttribute
- foreach (var propertyAttribute in propertyAttributes)
+ foreach (var propertyAttribute in arrayItemProperty.GetAttributes(false, OwningType).ToList())
{
- var arrayItemAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlArrayItemAttribute), Configuration),
- propertyAttribute.Arguments.Cast().Where(x => !string.Equals(x.Name, "Order", StringComparison.Ordinal)).ToArray());
- var namespacePresent = arrayItemAttribute.Arguments.OfType().Any(a => a.Name == "Namespace");
+ var arrayItemAttribute = AttributeDecl(
+ propertyAttribute.Arguments.Cast().Where(x => !string.Equals(x.Name, nameof(Order), StringComparison.Ordinal)).ToArray());
+ var namespacePresent = arrayItemAttribute.Arguments.OfType().Any(a => a.Name == Namespace);
if (!namespacePresent && !arrayItemProperty.XmlSchemaName.IsEmpty && !string.IsNullOrEmpty(arrayItemProperty.XmlSchemaName.Namespace))
- arrayItemAttribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(arrayItemProperty.XmlSchemaName.Namespace)));
+ arrayItemAttribute.Arguments.Add(new(Namespace, new CodePrimitiveExpression(arrayItemProperty.XmlSchemaName.Namespace)));
member.CustomAttributes.Add(arrayItemAttribute);
}
}
if (IsKey)
- {
- var keyAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "KeyAttribute", Configuration));
- member.CustomAttributes.Add(keyAttribute);
- }
+ member.CustomAttributes.Add(new(CodeUtilities.CreateTypeReference(Attributes.Key, Configuration)));
if (IsAny && Configuration.EntityFramework)
- {
member.CustomAttributes.Add(notMappedAttribute);
- }
Configuration.MemberVisitor(member, this);
}
@@ -1214,7 +985,7 @@ private IEnumerable GetAttributes(bool isArray, TypeMo
if (IsKey && XmlSchemaName == null)
{
- attributes.Add(new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlIgnoreAttribute), Configuration)));
+ attributes.Add(AttributeDecl());
return attributes;
}
@@ -1222,101 +993,82 @@ private IEnumerable GetAttributes(bool isArray, TypeMo
{
if (IsAny)
{
- var anyAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlAnyAttributeAttribute), Configuration));
+ var anyAttribute = AttributeDecl();
if (Order != null)
- anyAttribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(Order.Value)));
+ anyAttribute.Arguments.Add(new(nameof(Order), new CodePrimitiveExpression(Order.Value)));
attributes.Add(anyAttribute);
}
else
{
- attributes.Add(new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlAttributeAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))));
+ attributes.Add(AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name))));
}
}
else if (!isArray)
{
if (IsAny)
{
- var anyAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlAnyElementAttribute), Configuration));
+ var anyAttribute = AttributeDecl();
if (Order != null)
- anyAttribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(Order.Value)));
+ anyAttribute.Arguments.Add(new(nameof(Order), new CodePrimitiveExpression(Order.Value)));
attributes.Add(anyAttribute);
}
else
{
- if (!Configuration.SeparateSubstitutes && Substitutes.Any())
+ if (!Configuration.SeparateSubstitutes && Substitutes.Count > 0)
{
owningType ??= OwningType;
foreach (var substitute in Substitutes)
{
- var substitutedAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlElementAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(substitute.Element.QualifiedName.Name)),
- new CodeAttributeArgument("Type", new CodeTypeOfExpression(substitute.Type.GetReferenceFor(owningType.Namespace))),
- new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(substitute.Element.QualifiedName.Namespace)));
+ var substitutedAttribute = AttributeDecl(
+ new(new CodePrimitiveExpression(substitute.Element.QualifiedName.Name)),
+ new(nameof(XmlElementAttribute.Type), new CodeTypeOfExpression(substitute.Type.GetReferenceFor(owningType.Namespace))),
+ new(nameof(XmlElementAttribute.Namespace), new CodePrimitiveExpression(substitute.Element.QualifiedName.Namespace)));
if (Order != null)
- {
- substitutedAttribute.Arguments.Add(new CodeAttributeArgument("Order",
- new CodePrimitiveExpression(Order.Value)));
- }
+ substitutedAttribute.Arguments.Add(new(nameof(Order), new CodePrimitiveExpression(Order.Value)));
attributes.Add(substitutedAttribute);
}
}
- var attribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlElementAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)));
+ var attribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)));
if (Order != null)
- {
- attribute.Arguments.Add(new CodeAttributeArgument("Order",
- new CodePrimitiveExpression(Order.Value)));
- }
+ attribute.Arguments.Add(new(nameof(Order), new CodePrimitiveExpression(Order.Value)));
attributes.Add(attribute);
}
}
else
{
- var arrayAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlArrayAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)));
+ var arrayAttribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(XmlSchemaName.Name)));
if (Order != null)
- arrayAttribute.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(Order.Value)));
+ arrayAttribute.Arguments.Add(new(nameof(Order), new CodePrimitiveExpression(Order.Value)));
attributes.Add(arrayAttribute);
}
foreach (var args in attributes.Select(a => a.Arguments))
{
- bool namespacePrecalculated = args.OfType().Any(a => a.Name == "Namespace");
+ bool namespacePrecalculated = args.OfType().Any(a => a.Name == Namespace);
if (!namespacePrecalculated)
{
if (XmlNamespace != null)
- {
- args.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(XmlNamespace)));
- }
+ args.Add(new(Namespace, new CodePrimitiveExpression(XmlNamespace)));
if (Form == XmlSchemaForm.Qualified && IsAttribute)
{
if (XmlNamespace == null)
- {
- args.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(OwningType.XmlSchemaName.Namespace)));
- }
+ args.Add(new(Namespace, new CodePrimitiveExpression(OwningType.XmlSchemaName.Namespace)));
- args.Add(new CodeAttributeArgument("Form",
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CodeUtilities.CreateTypeReference(typeof(XmlSchemaForm), Configuration)),
- "Qualified")));
+ args.Add(new(nameof(Form), new CodeFieldReferenceExpression(TypeRefExpr(), nameof(XmlSchemaForm.Qualified))));
}
else if ((Form == XmlSchemaForm.Unqualified || Form == XmlSchemaForm.None) && !IsAttribute && !IsAny && XmlNamespace == null)
{
- args.Add(new CodeAttributeArgument("Form",
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CodeUtilities.CreateTypeReference(typeof(XmlSchemaForm), Configuration)),
- "Unqualified")));
+ args.Add(new(nameof(Form), new CodeFieldReferenceExpression(TypeRefExpr(), nameof(XmlSchemaForm.Unqualified))));
}
}
if (IsNillable && !(IsCollection && Type is SimpleModel m && m.ValueType.IsValueType) && !(IsNullable && Configuration.DoNotForceIsNullable))
- {
- args.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(true)));
- }
+ args.Add(new("IsNullable", new CodePrimitiveExpression(true)));
if (Type is SimpleModel simpleModel && simpleModel.UseDataTypeAttribute)
{
@@ -1327,12 +1079,13 @@ private IEnumerable GetAttributes(bool isArray, TypeMo
var name = xmlSchemaType.GetQualifiedName();
if (name.Namespace == XmlSchema.Namespace && name.Name != "anySimpleType")
{
- var dataType = new CodeAttributeArgument("DataType", new CodePrimitiveExpression(name.Name));
- args.Add(dataType);
+ args.Add(new("DataType", new CodePrimitiveExpression(name.Name)));
break;
}
else
+ {
xmlSchemaType = xmlSchemaType.BaseXmlSchemaType;
+ }
}
}
}
@@ -1346,24 +1099,14 @@ public class EnumValueModel
public string Name { get; set; }
public string Value { get; set; }
public bool IsDeprecated { get; set; }
- public List Documentation { get; private set; }
-
- public EnumValueModel()
- {
- Documentation = new List();
- }
+ public List Documentation { get; } = new();
}
public class EnumModel : TypeModel
{
- public List Values { get; set; }
-
- public EnumModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
- Values = new List();
- }
-
+ public List Values { get; set; } = new();
+
+ public EnumModel(GeneratorConfiguration configuration) : base(configuration) { }
public override CodeTypeDeclaration Generate()
{
var enumDeclaration = base.Generate();
@@ -1382,12 +1125,11 @@ public override CodeTypeDeclaration Generate()
var member = new CodeMemberField { Name = val.Name };
var docs = new List(val.Documentation);
- DocumentationModel.AddDescription(member.CustomAttributes, docs, Configuration);
+ AddDescription(member.CustomAttributes, docs);
if (val.Name != val.Value) // illegal identifier chars in value
{
- var enumAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlEnumAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(val.Value)));
+ var enumAttribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(val.Value)));
member.CustomAttributes.Add(enumAttribute);
}
@@ -1395,20 +1137,20 @@ public override CodeTypeDeclaration Generate()
{
// From .NET 3.5 XmlSerializer doesn't serialize objects with [Obsolete] >(
- var obsolete = new DocumentationModel { Language = "en", Text = "[Obsolete]" };
+ DocumentationModel obsolete = new() { Language = English, Text = "[Obsolete]" };
docs.Add(obsolete);
}
- member.Comments.AddRange(DocumentationModel.GetComments(docs, Configuration).ToArray());
+ member.Comments.AddRange(GetComments(docs).ToArray());
enumDeclaration.Members.Add(member);
}
if (RootElementName != null)
{
- var rootAttribute = new CodeAttributeDeclaration(CodeUtilities.CreateTypeReference(typeof(XmlRootAttribute), Configuration),
- new CodeAttributeArgument(new CodePrimitiveExpression(RootElementName.Name)),
- new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(RootElementName.Namespace)));
+ var rootAttribute = AttributeDecl(
+ new(new CodePrimitiveExpression(RootElementName.Name)),
+ new(nameof(XmlRootAttribute.Namespace), new CodePrimitiveExpression(RootElementName.Namespace)));
enumDeclaration.CustomAttributes.Add(rootAttribute);
}
Configuration.TypeVisitor(enumDeclaration, this);
@@ -1425,15 +1167,10 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
public class SimpleModel : TypeModel
{
public Type ValueType { get; set; }
- public List Restrictions { get; private set; }
- public bool UseDataTypeAttribute { get; set; }
+ public List Restrictions { get; } = new();
+ public bool UseDataTypeAttribute { get; set; } = true;
- public SimpleModel(GeneratorConfiguration configuration)
- : base(configuration)
- {
- Restrictions = new List();
- UseDataTypeAttribute = true;
- }
+ public SimpleModel(GeneratorConfiguration configuration) : base(configuration) { }
public static string GetCollectionDefinitionName(string typeName, GeneratorConfiguration configuration)
{
@@ -1452,8 +1189,10 @@ public static string GetCollectionImplementationName(string typeName, GeneratorC
private static string GetFullTypeName(string typeName, CodeTypeReference typeRef, Type type)
{
if (type.IsGenericTypeDefinition)
+ {
typeRef.TypeArguments.Add(typeName);
- else if (type == typeof(System.Array))
+ }
+ else if (type == typeof(Array))
{
typeRef.ArrayElementType = new CodeTypeReference(typeName);
typeRef.ArrayRank = 1;
@@ -1466,8 +1205,7 @@ private static string GetFullTypeName(string typeName, CodeTypeReference typeRef
CSharpProvider.GenerateCodeFromExpression(typeOfExpr, writer, new CodeGeneratorOptions());
var fullTypeName = writer.ToString();
Debug.Assert(fullTypeName.StartsWith("typeof(") && fullTypeName.EndsWith(")"));
- fullTypeName = fullTypeName.Substring(7, fullTypeName.Length - 8);
- return fullTypeName;
+ return fullTypeName.Substring(7, fullTypeName.Length - 8);
}
public override CodeTypeDeclaration Generate()
@@ -1494,12 +1232,8 @@ public override CodeTypeReference GetReferenceFor(NamespaceModel referencingName
{
var collectionType = forInit ? (Configuration.CollectionImplementationType ?? Configuration.CollectionType) : Configuration.CollectionType;
- if (collectionType.IsGenericType)
- type = collectionType.MakeGenericType(type);
- else if (collectionType == typeof(System.Array))
- type = type.MakeArrayType();
- else
- type = collectionType;
+ type = collectionType.IsGenericType ? collectionType.MakeGenericType(type)
+ : collectionType == typeof(Array) ? type.MakeArrayType() : collectionType;
}
return CodeUtilities.CreateTypeReference(type, Configuration);
@@ -1528,24 +1262,15 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
}
else if (type == typeof(DateTime))
{
- var rv = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(CodeUtilities.CreateTypeReference(typeof(DateTime), Configuration)),
- "Parse", new CodePrimitiveExpression(defaultString));
- return rv;
+ return new CodeMethodInvokeExpression(TypeRefExpr(), nameof(DateTime.Parse), new CodePrimitiveExpression(defaultString));
}
else if (type == typeof(TimeSpan))
{
- var rv = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(CodeUtilities.CreateTypeReference(typeof(XmlConvert), Configuration)),
- "ToTimeSpan", new CodePrimitiveExpression(defaultString));
- return rv;
+ return new CodeMethodInvokeExpression(TypeRefExpr(), nameof(XmlConvert.ToTimeSpan), new CodePrimitiveExpression(defaultString));
}
else if (type == typeof(bool) && !string.IsNullOrWhiteSpace(defaultString))
{
- if (defaultString == "0")
- return new CodePrimitiveExpression(false);
- else if (defaultString == "1")
- return new CodePrimitiveExpression(true);
- else
- return new CodePrimitiveExpression(Convert.ChangeType(defaultString, ValueType));
+ return new CodePrimitiveExpression(defaultString == "0" ? false : defaultString == "1" ? true : Convert.ChangeType(defaultString, ValueType));
}
else if (type == typeof(byte[]) && defaultString != null)
{
@@ -1556,8 +1281,7 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
// For whatever reason, CodeDom will not generate a semicolon for the assignment statement if CodeArrayCreateExpression
// is used alone. Casting the value to the same type to work around this issue.
- var rv = new CodeCastExpression(typeof(byte[]), new CodeArrayCreateExpression(typeof(byte), byteValues));
- return rv;
+ return new CodeCastExpression(typeof(byte[]), new CodeArrayCreateExpression(typeof(byte), byteValues));
}
else if (type == typeof(double) && !string.IsNullOrWhiteSpace(defaultString))
{
@@ -1573,9 +1297,7 @@ public override CodeExpression GetDefaultValueFor(string defaultString, bool att
public IEnumerable GetRestrictionAttributes()
{
foreach (var attribute in Restrictions.Where(x => x.IsSupported).Select(r => r.GetAttribute()).Where(a => a != null))
- {
yield return attribute;
- }
var minInclusive = Restrictions.OfType().FirstOrDefault(x => x.IsSupported);
var maxInclusive = Restrictions.OfType().FirstOrDefault(x => x.IsSupported);
@@ -1583,27 +1305,95 @@ public IEnumerable GetRestrictionAttributes()
if (minInclusive != null && maxInclusive != null)
{
var rangeAttribute = new CodeAttributeDeclaration(
- CodeUtilities.CreateTypeReference("System.ComponentModel.DataAnnotations", "RangeAttribute", Configuration),
- new CodeAttributeArgument(new CodeTypeOfExpression(minInclusive.Type)),
- new CodeAttributeArgument(new CodePrimitiveExpression(minInclusive.Value)),
- new CodeAttributeArgument(new CodePrimitiveExpression(maxInclusive.Value)));
+ CodeUtilities.CreateTypeReference(Attributes.Range, Configuration),
+ new(new CodeTypeOfExpression(minInclusive.Type)),
+ new(new CodePrimitiveExpression(minInclusive.Value)),
+ new(new CodePrimitiveExpression(maxInclusive.Value)));
// see https://github.com/mganss/XmlSchemaClassGenerator/issues/268
if (Configuration.NetCoreSpecificCode)
{
if (minInclusive.Value.Contains(".") || maxInclusive.Value.Contains("."))
- {
- rangeAttribute.Arguments.Add(new CodeAttributeArgument("ParseLimitsInInvariantCulture", new CodePrimitiveExpression(true)));
- }
+ rangeAttribute.Arguments.Add(new("ParseLimitsInInvariantCulture", new CodePrimitiveExpression(true)));
if (minInclusive.Type != typeof(int) && minInclusive.Type != typeof(double))
- {
- rangeAttribute.Arguments.Add(new CodeAttributeArgument("ConvertValueInInvariantCulture", new CodePrimitiveExpression(true)));
- }
+ rangeAttribute.Arguments.Add(new("ConvertValueInInvariantCulture", new CodePrimitiveExpression(true)));
}
yield return rangeAttribute;
}
}
}
+
+ public class GeneratorModel
+ {
+ protected const string OnPropertyChanged = nameof(OnPropertyChanged);
+ protected const string EqualsMethod = nameof(object.Equals);
+ protected const string HasValue = nameof(Nullable.HasValue);
+
+ protected const string GetSet = " { get; set; }";
+
+ protected const string English = "en";
+ protected const string German = "de";
+
+ protected GeneratorModel(GeneratorConfiguration configuration) => Configuration = configuration;
+
+ public GeneratorConfiguration Configuration { get; }
+
+ protected CodeTypeReferenceExpression TypeRefExpr() => new(TypeRef());
+
+ protected CodeAttributeDeclaration AttributeDecl(params CodeAttributeArgument[] args) => new(TypeRef(), args);
+
+ private protected CodeAttributeDeclaration AttributeDecl(TypeInfo attribute, CodeAttributeArgument arg)
+ => new(CodeUtilities.CreateTypeReference(attribute, Configuration), arg);
+
+ protected CodeTypeReference TypeRef() => CodeUtilities.CreateTypeReference(typeof(T), Configuration);
+
+ protected CodeTypeReference NullableTypeRef(CodeTypeReference typeReference)
+ {
+ var nullableType = CodeUtilities.CreateTypeReference(typeof(Nullable<>), Configuration);
+ nullableType.TypeArguments.Add(typeReference);
+ return nullableType;
+ }
+ public static bool DisableComments { get; set; }
+
+ protected IEnumerable GetComments(IList docs)
+ {
+ if (DisableComments || docs.Count == 0)
+ yield break;
+
+ yield return new CodeCommentStatement("", true);
+
+ foreach (var doc in docs
+ .Where(d => string.IsNullOrEmpty(d.Language) || Configuration.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase)))
+ .OrderBy(d => d.Language))
+ {
+ var text = doc.Text;
+ var comment = $"{CodeUtilities.NormalizeNewlines(text).Trim()}";
+ yield return new CodeCommentStatement(comment, true);
+ }
+
+ yield return new CodeCommentStatement("", true);
+ }
+
+ protected void AddDescription(CodeAttributeDeclarationCollection attributes, IEnumerable docs)
+ {
+ if (!Configuration.GenerateDescriptionAttribute || DisableComments || !docs.Any()) return;
+
+ var doc = GetSingleDoc(docs.Where(d => string.IsNullOrEmpty(d.Language) || Configuration.CommentLanguages.Any(l => d.Language.StartsWith(l, StringComparison.OrdinalIgnoreCase))));
+
+ if (doc != null)
+ {
+ var descriptionAttribute = AttributeDecl(new CodeAttributeArgument(new CodePrimitiveExpression(Regex.Replace(doc.Text, @"\s+", " ").Trim())));
+ attributes.Add(descriptionAttribute);
+ }
+ }
+
+ private static DocumentationModel GetSingleDoc(IEnumerable docs)
+ {
+ return docs.Count() == 1 ? docs.Single()
+ : docs.FirstOrDefault(d => string.IsNullOrEmpty(d.Language) || d.Language.StartsWith(English, StringComparison.OrdinalIgnoreCase))
+ ?? docs.FirstOrDefault();
+ }
+ }
}