I'm designing a validation service and I'm debating between two different method signatures for Validate(). Both use lambda Expressions to get the object type and property of the object to validate the given value. There are defined as:
public interface IValidationService
{
/// <summary>
/// Validates the value of the property returned by the property expression.
/// </summary>
/// <typeparam name="T">The type of the object to validate.</typeparam>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="propertyExpression">The property expression.</param>
/// <param name="value">The value.</param>
/// <returns></returns>
TProperty Validate<T, TProperty>(Expression<Func<T, TProperty>> propertyExpression, TProperty value);
/// <summary>
/// Validates the value of the property returned by the property expression.
/// </summary>
/// <typeparam name="T">The type of the object to validate.</typeparam>
/// <param name="propertyExpression">The property expression.</param>
/// <param name="value">The value.</param>
/// <returns></returns>
object Validate<T>(Expression<Func<T, object>> propertyExpression, object value);
}
Here's a unit test for each so you can see the difference in usage:
[Test]
public void ValidateCustomerId_Method1()
{
string id = "123456789123";
string validatedId = _validationService.Validate<Customer, string>(x => x.Id, id);
Assert.That(validatedId, Is.EqualTo("123456789"));
}
[Test]
public void ValidateCustomerId_Method2()
{
string id = "123456789123";
string validatedId = (string) _validationService.Validate<Customer>(x => x.Id, id);
Assert.That(validatedId, Is.EqualTo("123456789"));
}
The first has two type parameters, one for the object type (T) and one for the property/value type (TProperty). This one is nice because the return type is TProperty, but its also a bit annoying because it has two type parameters.
The second has only one type parameter for the object type. The value is an object and also returns an object. This is nice because it only has one type parameter, but its also a bit annoying because I'll have to cast the return type from object to the property/value type.
I suppose another option would be adding a type parameter to the interface, IValidationService, which would eliminate the object type parameter (T) in both signatures:
public interface IValidationService<T>
{
TProperty Validate<TProperty>(Expression<Func<T, TProperty>> propertyExpression, TProperty value);
object Validate(Expression<Func<T, object>> propertyExpression, object value);
}
Which signature makes the most sense and why?