No I'm not thinking that, I'm saying that implementing a non-generic base interface like
public interface IValidator {
bool Validate(object obj);
}
is pointless because you'll have to do the same type checking/casting in Validate you would have to do in a wrapper which implemented IValidator<object>. Requiring a base interface is worse because you'll have to implement the same boilerplate implementation of Validate(object) in every implementing class - see IEnumerable/IEnumerable<T> as an example.> Obviously this library will need to do run-time casting of types
You've linked to a clojure library which is dynamically typed so I don't see how this is relevant. It's not obvious to me why a C# version would require casting.
Task/Task<T> does follow the pattern but they could have simply introduced a Unit type in the BCL and replaced the non-generic Task type with Task<Unit> instead.
> To run all of these validators against a given class you have three (un)reasonable choices:
You only need to write one wrapper class which encapsulates the cast you'd have to do anyway in a non-generic IValidator interface:
public class Wrapper<T, TBase> : IValidator<TBase>
{
private readonly IValidator<T> inner;
public Wrapper(IValidator<T> v)
{
this.inner = v;
}
public bool Validate(TBase b)
{
if(b is T)
{
return this.inner.Validate((T)(object)b);
}
else return false;
}
}