don't reinvent the wheel; move attribute validation logic from Oms to AttributeImplementation

This commit is contained in:
Michael Becker 2025-10-26 09:43:38 -04:00
parent 3a96529a21
commit 0e40deb35b
7 changed files with 70 additions and 86 deletions

View File

@ -30,10 +30,13 @@ public abstract class AttributeImplementation<T> : AttributeImplementation
}
return defaultValue;
}
protected override IEnumerable<Type>? ValidDataTypes => [ typeof(T) ];
}
public abstract class AttributeImplementation : ClassImplementation
{
protected virtual IEnumerable<Type>? 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);
}
}

View File

@ -54,9 +54,4 @@ public class BooleanAttributeImplementation : AttributeImplementation<bool>
objCell.Add("value", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance));
objCell.Add("text", oms.GetAttributeValue<bool>(targetInstance, elementContentInstance) ? "Yes" : "No");
}
protected override bool IsValidValueInternal(object value)
{
return value is bool;
}
}

View File

@ -61,9 +61,4 @@ public class DateAttributeImplementation : AttributeImplementation<DateTime>
objCell.Add("text", dt.ToString());
objCell.Add("dateTimePrecision", "DAY");
}
protected override bool IsValidValueInternal(object value)
{
return value is DateTime;
}
}

View File

@ -55,9 +55,21 @@ public class NumericAttributeImplementation : AttributeImplementation<decimal>
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));
}
}
}
}

View File

@ -78,8 +78,25 @@ public class TextAttributeImplementation : AttributeImplementation<string>
}
}
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));
}
}
}
}

View File

@ -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<string>(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<AttributeImplementation> attrs = ClassImplementations.GetAll<AttributeImplementation>();
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<InstanceHandle> 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;
}

View File

@ -190,18 +190,6 @@ public class OmsContext
}
}
}
private void ValidateAttributeConstraints(InstanceHandle parm, object value)
{
Guid parentClassGuid = Oms.GetGlobalIdentifier(Oms.GetParentClass(parm));
IEnumerable<AttributeImplementation> attrs = Oms.ClassImplementations.GetAll<AttributeImplementation>();
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;