patterncsharpMinor
Validating the value of a property of an object
Viewed 0 times
thevaluevalidatingpropertyobject
Problem
This code snippet is intended for validating the value of a property of an object. The min and max range is supplied as an .xml file like Nhibernate .hbm files. Since the data-type of the property is also read from the .xml file, we can only know the type of the property at run-time.
Is there any better way of improving the code in C# and .NET 2.0?
```
public static void ValidateMinMax(Property prop, Object value)
{
Type type = Type.GetType(prop.TypeName);
Object minValue = PropertyDataExtractor.GetMinValue(prop);
Object maxValue = PropertyDataExtractor.GetMaxValue(prop);
Object actualVaue = null;
bool minValueOk = false;
bool maxValueOk = false;
if (minValue != null)
{
switch (type.Name)
{
case "Boolean":
break;
case "SByte":
actualVaue = Convert.ToSByte(value);
if (actualVaue != null)
{
minValueOk = ((sbyte)minValue) = ((sbyte)actualVaue);
}
else
{
maxValue = true;
}
break;
case "Byte":
actualVaue = Convert.ToByte(value);
if (actualVaue != null)
{
maxValueOk = ((byte)minValue) >= ((byte)actualVaue);
}
else
{
maxValue = true;
}
break;
case "Byte[]":
break;
case "DateTime":
actualVaue = Convert.ToDateTime(value);
if (actualVaue != null)
{
maxValueOk = ((DateTime)maxValue).Date >= ((DateTime)actualVaue).Date;
}
Is there any better way of improving the code in C# and .NET 2.0?
```
public static void ValidateMinMax(Property prop, Object value)
{
Type type = Type.GetType(prop.TypeName);
Object minValue = PropertyDataExtractor.GetMinValue(prop);
Object maxValue = PropertyDataExtractor.GetMaxValue(prop);
Object actualVaue = null;
bool minValueOk = false;
bool maxValueOk = false;
if (minValue != null)
{
switch (type.Name)
{
case "Boolean":
break;
case "SByte":
actualVaue = Convert.ToSByte(value);
if (actualVaue != null)
{
minValueOk = ((sbyte)minValue) = ((sbyte)actualVaue);
}
else
{
maxValue = true;
}
break;
case "Byte":
actualVaue = Convert.ToByte(value);
if (actualVaue != null)
{
maxValueOk = ((byte)minValue) >= ((byte)actualVaue);
}
else
{
maxValue = true;
}
break;
case "Byte[]":
break;
case "DateTime":
actualVaue = Convert.ToDateTime(value);
if (actualVaue != null)
{
maxValueOk = ((DateTime)maxValue).Date >= ((DateTime)actualVaue).Date;
}
Solution
Here's an attempt to use a bit of polymorphism. While doing this some things I did note were:
1) The if statement at the end means that !minValueOk and !maxValueOk are irrelevant and will never be true. The first if should be !minValueOk and !maxValueOk rather than !(minValueOk && maxValueOk.
2) Assuming value is never null for some of the checks you do not need to double check for null. For example
3) I typically try not to through Exception where I can. Perhaps a custom exception might be worthwhile here.
Here's my attempt at a refactor. I'm not 100% sure it will compile but it should at least give an idea:
The new Validate method:
Using a custom exception and a Factory class to create the objects that will do the validation
The base validator class
Examples of specific validator classes
1) The if statement at the end means that !minValueOk and !maxValueOk are irrelevant and will never be true. The first if should be !minValueOk and !maxValueOk rather than !(minValueOk && maxValueOk.
2) Assuming value is never null for some of the checks you do not need to double check for null. For example
Convert.ToSByte(value) should always return a non-null value assuming it will convert.3) I typically try not to through Exception where I can. Perhaps a custom exception might be worthwhile here.
Here's my attempt at a refactor. I'm not 100% sure it will compile but it should at least give an idea:
The new Validate method:
public static void ValidateMinMax(object prop, Object value)
{
PropertyValidator validator = new PropertyValidatorFactory().CreateValidator(prop.GetType().Name);
if (!validator.Validate(prop, value))
{
if (!isMinValid && !isMaxValid)
{
message = PropertyDataExtractor.GetMinValueErrorMessage(prop) + " " + PropertyDataExtractor.GetMaxValueErrorMessage(prop);
}
else if (!isMinValid)
{
message = PropertyDataExtractor.GetMinValueErrorMessage(prop);
}
else
{
message = PropertyDataExtractor.GetMaxValueErrorMessage(prop);
}
return InvalidPropertyRangeException("Property : " + PropertyDataExtractor.GetName(prop) + ".\nMessage : " + message);
}
}Using a custom exception and a Factory class to create the objects that will do the validation
class InvalidPropertyRangeException : Exception
{
public InvalidPropertyRangeException(string message) : base(message)
{
}
}
class PropertyValidatorFactory
{
public PropertyValidator CreateValidator(string typeName)
{
switch (typeName)
{
case "Boolean":
return new EmptyValidator();
case "String":
return new StringValidator();
// Rest of validators go here
default:
throw new NotImplementedException(string.Format("Type {0} is not supported", typeName));
}
}
}The base validator class
abstract class PropertyValidator
{
public bool IsMinValid { get; private set; }
public bool IsMaxValid { get; private set; }
protected Object OriginalValue { get; private set; }
protected PropertyValidator()
{
IsMinValid = IsMaxValid = true;
}
public bool Validate(object prop, Object value)
{
if(value == null)
{
throw new NullReferenceException("Value supplied for validation is null");
}
Object minValue = PropertyDataExtractor.GetMinValue(prop);
Object maxValue = PropertyDataExtractor.GetMaxValue(prop);
if(minValue == null && maxValue == null)
{
return true;
}
OriginalValue = value;
return IsValid(minValue, maxValue);
}
private bool IsValid(object minValue, object maxValue)
{
IsMinValid = ValidateMinimum(minValue);
IsMaxValid = ValidateMaximum(maxValue);
return IsMinValid && IsMaxValid;
}
protected abstract bool ValidateMinimum(object minValue);
protected abstract bool ValidateMaximum(object maxValue);
}Examples of specific validator classes
class EmptyValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
return true;
}
protected override bool ValidateMaximum(object maxValue)
{
return true;
}
}
class SbyteValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
sbyte actualVaue = GetValue();
return ((sbyte)minValue) = actualVaue;
}
private sbyte GetValue()
{
return Convert.ToSByte(OriginalValue);
}
}
class StringValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
string actualVaue = GetValue();
if (actualVaue != null)
{
return ((int)minValue) = actualVaue.Length;
}
return false;
}
private string GetValue()
{
return Convert.ToString(OriginalValue);
}
}Code Snippets
public static void ValidateMinMax(object prop, Object value)
{
PropertyValidator validator = new PropertyValidatorFactory().CreateValidator(prop.GetType().Name);
if (!validator.Validate(prop, value))
{
if (!isMinValid && !isMaxValid)
{
message = PropertyDataExtractor.GetMinValueErrorMessage(prop) + " " + PropertyDataExtractor.GetMaxValueErrorMessage(prop);
}
else if (!isMinValid)
{
message = PropertyDataExtractor.GetMinValueErrorMessage(prop);
}
else
{
message = PropertyDataExtractor.GetMaxValueErrorMessage(prop);
}
return InvalidPropertyRangeException("Property : " + PropertyDataExtractor.GetName(prop) + ".\nMessage : " + message);
}
}class InvalidPropertyRangeException : Exception
{
public InvalidPropertyRangeException(string message) : base(message)
{
}
}
class PropertyValidatorFactory
{
public PropertyValidator CreateValidator(string typeName)
{
switch (typeName)
{
case "Boolean":
return new EmptyValidator();
case "String":
return new StringValidator();
// Rest of validators go here
default:
throw new NotImplementedException(string.Format("Type {0} is not supported", typeName));
}
}
}abstract class PropertyValidator
{
public bool IsMinValid { get; private set; }
public bool IsMaxValid { get; private set; }
protected Object OriginalValue { get; private set; }
protected PropertyValidator()
{
IsMinValid = IsMaxValid = true;
}
public bool Validate(object prop, Object value)
{
if(value == null)
{
throw new NullReferenceException("Value supplied for validation is null");
}
Object minValue = PropertyDataExtractor.GetMinValue(prop);
Object maxValue = PropertyDataExtractor.GetMaxValue(prop);
if(minValue == null && maxValue == null)
{
return true;
}
OriginalValue = value;
return IsValid(minValue, maxValue);
}
private bool IsValid(object minValue, object maxValue)
{
IsMinValid = ValidateMinimum(minValue);
IsMaxValid = ValidateMaximum(maxValue);
return IsMinValid && IsMaxValid;
}
protected abstract bool ValidateMinimum(object minValue);
protected abstract bool ValidateMaximum(object maxValue);
}class EmptyValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
return true;
}
protected override bool ValidateMaximum(object maxValue)
{
return true;
}
}
class SbyteValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
sbyte actualVaue = GetValue();
return ((sbyte)minValue) <= actualVaue;
}
protected override bool ValidateMaximum(object maxValue)
{
sbyte actualVaue = GetValue();
return ((sbyte)maxValue) >= actualVaue;
}
private sbyte GetValue()
{
return Convert.ToSByte(OriginalValue);
}
}
class StringValidator : PropertyValidator
{
protected override bool ValidateMinimum(object minValue)
{
string actualVaue = GetValue();
if (actualVaue != null)
{
return ((int)minValue) <= actualVaue.Length;
}
return false;
}
protected override bool ValidateMaximum(object maxValue)
{
string actualVaue = GetValue();
if (actualVaue != null)
{
return ((int)maxValue) >= actualVaue.Length;
}
return false;
}
private string GetValue()
{
return Convert.ToString(OriginalValue);
}
}Context
StackExchange Code Review Q#18175, answer score: 3
Revisions (0)
No revisions yet.