After creating a class with property set/get and creating NUnit tests to stress the methods, I found I was typing the same numbers again and again for the maximum length of the string value of the property. Worse, it was too easy to make a typo and have my NUnit test not reflect the true expected maximum length.
So I created a MaxLengthAtrribute class which defines the maximum length of a property (incidently based on a field size in a database). For example, a Surname property get/set method might look like this;
[MaxLength(50)]
public string Surname
{
get { return _surname; }
set {
if (value == null)
{
_surname = String.Empty;
}
else
{
ValidateStringProperty(this, "Surname", value);
_surname = value;
}
}
}
The method, ValidateStringProperty, uses reflection to extract the maximum length from the attribute as shown below;
public static void ValidateStringProperty(object dataObject,
string propertyName, string newValue)
{
int maxLength = ((MaxLengthAttribute)DataObject.GetType().GetProperty(propertyName).GetCustomAttributes(typeof(MaxLengthAttribute), false)[0]).MaxLength;
if (newValue.Length > maxLength)
{
throw new ArgumentException("Value should contain between 0 and " + maxLength.ToString() + "characters.", propertyName);
}
}
In a similar manner the NUnit test for this string property obtains the maximum length from the MaxLength attribute and then tests setting strings of length 0 to the maximum value (comparing get is the same as the value just set). The NUnit test also tries to set a string value of maximum length+1 to check for ArgumentException being thrown.
Now I can modify the maximum length of the property by changing the maximum length attribute, and the validation and NUnit test are instantly updated to match.
The question: Is this a good way of tying together the property method checking and NUnit testing in a consistent manner? Is there a signficant penality hit from the overhead of reflection every time a property is set to outweigh the benefit of the maximum length only existing in a single location?
--------------------------------------
UPDATE - 27 Aug 2005
Reflection, as expected is way slower, coming last. Interestingly a single method, using a switch statement to return a max length for any property, also had a performance hit. The fastest by far was having a matching MaxLengthXXXX read only property for each XXXX property.
Of course, the MaxLength attribute is by far the most elegant and places all the information in a single location. Also, slow is relative, even with 100000 property set calls with reflection it took less than 1 second (on my 1.6/1Mb Centrino).