From 0e40deb35b3f9ef7a544d17be2c30da2e505f4fd Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Sun, 26 Oct 2025 09:43:38 -0400 Subject: [PATCH] don't reinvent the wheel; move attribute validation logic from Oms to AttributeImplementation --- .../lib/Mocha.Core/AttributeImplementation.cs | 19 ++++- .../BooleanAttributeImplementation.cs | 5 -- .../DateAttributeImplementation.cs | 5 -- .../NumericAttributeImplementation.cs | 18 ++++- .../TextAttributeImplementation.cs | 21 +++++- mocha-dotnet/src/lib/Mocha.Core/Oms.cs | 74 +++++-------------- mocha-dotnet/src/lib/Mocha.Core/OmsContext.cs | 14 +--- 7 files changed, 70 insertions(+), 86 deletions(-) diff --git a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementation.cs index bbde3ec..00bd958 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementation.cs @@ -30,10 +30,13 @@ public abstract class AttributeImplementation : AttributeImplementation } return defaultValue; } + + protected override IEnumerable? ValidDataTypes => [ typeof(T) ]; } public abstract class AttributeImplementation : ClassImplementation { + protected virtual IEnumerable? ValidDataTypes { get; } protected abstract object? ConvertFromInternal(Oms oms, object? value); public object? ReadDerivedData(BinaryReader br) @@ -53,9 +56,19 @@ public abstract class AttributeImplementation : ClassImplementation ExecuteBuildElementInternal(oms, targetInstance, elementContent, elementContentInstance, objCell); } - protected abstract bool IsValidValueInternal(object value); - public bool IsValidValue(object value) + protected virtual void ValidateInternal(Oms oms, InstanceHandle attributeInstance, object value) { - return IsValidValueInternal(value); + // do nothing by default + } + public void Validate(Oms oms, InstanceHandle attributeInstance, object value) + { + if (ValidDataTypes != null) + { + if (value != null && !ValidDataTypes.Contains(value.GetType())) + { + throw new ArgumentException(String.Format("value {0} cannot be converted to attribute type `{1}`", value is string ? "\"" + value.ToString() + "\"" : value, oms.GetInstanceText(attributeInstance))); + } + } + ValidateInternal(oms, attributeInstance, value); } } diff --git a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/BooleanAttributeImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/BooleanAttributeImplementation.cs index a81025b..8e6c83d 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/BooleanAttributeImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/BooleanAttributeImplementation.cs @@ -54,9 +54,4 @@ public class BooleanAttributeImplementation : AttributeImplementation objCell.Add("value", oms.GetAttributeValue(targetInstance, elementContentInstance)); objCell.Add("text", oms.GetAttributeValue(targetInstance, elementContentInstance) ? "Yes" : "No"); } - - protected override bool IsValidValueInternal(object value) - { - return value is bool; - } } \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/DateAttributeImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/DateAttributeImplementation.cs index 79fd89c..a78ac87 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/DateAttributeImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/DateAttributeImplementation.cs @@ -61,9 +61,4 @@ public class DateAttributeImplementation : AttributeImplementation objCell.Add("text", dt.ToString()); objCell.Add("dateTimePrecision", "DAY"); } - - protected override bool IsValidValueInternal(object value) - { - return value is DateTime; - } } \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/NumericAttributeImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/NumericAttributeImplementation.cs index 49d9628..cc66390 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/NumericAttributeImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/NumericAttributeImplementation.cs @@ -55,9 +55,21 @@ public class NumericAttributeImplementation : AttributeImplementation objCell.Add("precision", 6); objCell.Add("format", "#0.######"); } - - protected override bool IsValidValueInternal(object value) + protected override void ValidateInternal(Oms oms, InstanceHandle attributeInstance, object value) { - return value is decimal; + if (oms.TryGetAttributeValue(attributeInstance, oms.GetInstance(KnownAttributeGuids.Numeric.MinimumValue), out decimal minimumValue)) + { + if (((decimal)value) < minimumValue) + { + throw new ArgumentOutOfRangeException(String.Format("value for NumericAttribute must be greater than {0}", minimumValue - 1)); + } + } + if (oms.TryGetAttributeValue(attributeInstance, oms.GetInstance(KnownAttributeGuids.Numeric.MaximumValue), out decimal maximumValue)) + { + if (((decimal)value) > maximumValue) + { + throw new ArgumentOutOfRangeException(String.Format("value for NumericAttribute must be greater than {0}", maximumValue - 1)); + } + } } } \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/TextAttributeImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/TextAttributeImplementation.cs index b26e9e4..7ac51a4 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/TextAttributeImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/AttributeImplementations/TextAttributeImplementation.cs @@ -78,8 +78,25 @@ public class TextAttributeImplementation : AttributeImplementation } } - protected override bool IsValidValueInternal(object value) + protected override void ValidateInternal(Oms oms, InstanceHandle attributeInstance, object value) { - return value is string; + if (!(value is string)) + { + throw new ArgumentException("value for TextAttribute must be System.String"); + } + if (oms.TryGetAttributeValue(attributeInstance, oms.GetInstance(KnownAttributeGuids.Numeric.MinimumLength), out decimal minimumLength)) + { + if (((string)value).Length < minimumLength) + { + throw new ArgumentOutOfRangeException(String.Format("value for TextAttribute must be greater than {0} characters", minimumLength - 1)); + } + } + if (oms.TryGetAttributeValue(attributeInstance, oms.GetInstance(KnownAttributeGuids.Numeric.MaximumLength), out decimal maximumLength)) + { + if (((string)value).Length > maximumLength) + { + throw new ArgumentOutOfRangeException(String.Format("value for TextAttribute must be less than {0} characters", maximumLength + 1)); + } + } } } \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs index 42e15d6..57cd478 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs @@ -908,7 +908,11 @@ public abstract class Oms } } - private void ValidateConstraintsForAttribute(InstanceHandle source, InstanceHandle attribute, object value) + public void ValidateConstraintsForAttribute(InstanceHandle attribute, object value) + { + ValidateConstraintsForAttribute(InstanceHandle.Empty, attribute, value); + } + public void ValidateConstraintsForAttribute(InstanceHandle source, InstanceHandle attribute, object value) { if (!ValidateConstraints) return; @@ -924,11 +928,10 @@ public abstract class Oms InstanceHandle a_NumericAttribute = GetInstance(KnownInstanceGuids.Classes.NumericAttribute); InstanceHandle a_DateAttribute = GetInstance(KnownInstanceGuids.Classes.DateAttribute); - InstanceHandle sourceParentClass = GetParentClass(source); - bool Verify_Classes_Contain_Attributes = false; - if (Verify_Classes_Contain_Attributes) + if (Verify_Classes_Contain_Attributes && source != InstanceHandle.Empty) { + InstanceHandle sourceParentClass = GetParentClass(source); if (!RecursiveClassHasAttribute(sourceParentClass, attribute)) { string name = GetAttributeValue(attribute, GetInstance(KnownAttributeGuids.Text.Name)); @@ -936,54 +939,15 @@ public abstract class Oms throw new ArgumentException(String.Format("Undefined attribute `{0}` on class `{1}`", name ?? GetGlobalIdentifier(attribute).ToString("b"), sourceParentClassName ?? GetGlobalIdentifier(sourceParentClass).ToString("b"))); } } - - if (IsInstanceOf(attribute, a_TextAttribute)) + + Guid parentClassGuid = GetGlobalIdentifier(GetParentClass(attribute)); + IEnumerable attrs = ClassImplementations.GetAll(); + foreach (AttributeImplementation impl in attrs) { - if (!(value is string)) + if (impl.ClassGuid == parentClassGuid) { - throw new ArgumentException("value for TextAttribute must be System.String"); - } - if (TryGetAttributeValue(attribute, GetInstance(KnownAttributeGuids.Numeric.MinimumLength), out decimal minimumLength)) - { - if (((string)value).Length < minimumLength) - { - throw new ArgumentOutOfRangeException(String.Format("value for TextAttribute must be greater than {0} characters", minimumLength - 1)); - } - } - if (TryGetAttributeValue(attribute, GetInstance(KnownAttributeGuids.Numeric.MaximumLength), out decimal maximumLength)) - { - if (((string)value).Length > maximumLength) - { - throw new ArgumentOutOfRangeException(String.Format("value for TextAttribute must be less than {0} characters", maximumLength + 1)); - } - } - } - else if (IsInstanceOf(attribute, a_BooleanAttribute)) - { - if (!(value is bool)) - { - throw new ArgumentException("value for BooleanAttribute must be System.Boolean"); - } - } - else if (IsInstanceOf(attribute, a_NumericAttribute)) - { - if (!(value is decimal)) - { - throw new ArgumentException("value for NumericAttribute must be System.Decimal"); - } - if (TryGetAttributeValue(attribute, GetInstance(KnownAttributeGuids.Numeric.MinimumValue), out decimal minimumValue)) - { - if (((decimal)value) < minimumValue) - { - throw new ArgumentOutOfRangeException(String.Format("value for NumericAttribute must be greater than {0}", minimumValue - 1)); - } - } - if (TryGetAttributeValue(attribute, GetInstance(KnownAttributeGuids.Numeric.MaximumValue), out decimal maximumValue)) - { - if (((decimal)value) > maximumValue) - { - throw new ArgumentOutOfRangeException(String.Format("value for NumericAttribute must be greater than {0}", maximumValue - 1)); - } + impl.Validate(this, attribute, value); + // throw new ArgumentException(String.Format("value {0} cannot be converted to a `{1}`", value is string ? "\"" + value + "\"" : value, Oms.GetInstanceText(Oms.GetParentClass(parm))), nameof(value)); } } } @@ -1001,14 +965,14 @@ public abstract class Oms IReadOnlyCollection superclasses = GetRelatedInstances(sourceParentClass, GetInstance(KnownRelationshipGuids.Class__has_super__Class)); if (superclasses != null) { - foreach (InstanceHandle ir in superclasses) - { - if (RecursiveClassHasAttribute(ir, attribute)) + foreach (InstanceHandle ir in superclasses) { - return true; + if (RecursiveClassHasAttribute(ir, attribute)) + { + return true; + } } } - } } return false; } diff --git a/mocha-dotnet/src/lib/Mocha.Core/OmsContext.cs b/mocha-dotnet/src/lib/Mocha.Core/OmsContext.cs index b8f4c32..971474a 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/OmsContext.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/OmsContext.cs @@ -190,18 +190,6 @@ public class OmsContext } } } - private void ValidateAttributeConstraints(InstanceHandle parm, object value) - { - Guid parentClassGuid = Oms.GetGlobalIdentifier(Oms.GetParentClass(parm)); - IEnumerable attrs = Oms.ClassImplementations.GetAll(); - foreach (AttributeImplementation impl in attrs) - { - if (impl.ClassGuid == parentClassGuid && !impl.IsValidValue(value)) - { - throw new ArgumentException(String.Format("value {0} cannot be converted to a `{1}`", value is string ? "\"" + value + "\"" : value, Oms.GetInstanceText(Oms.GetParentClass(parm))), nameof(value)); - } - } - } public void SetWorkData(IInstanceReference parm, object? value) { @@ -236,7 +224,7 @@ public class OmsContext } else { - ValidateAttributeConstraints(parm, value); + Oms.ValidateConstraintsForAttribute(parm, value); } } _WorkData[parm] = value;