Я считаю, что это единственный способ достичь того, чего я хочу, но я хотел бы показать это, чтобы увидеть, есть ли решение, которое не требует использования динамического / отражения.
У меня есть следующая иерархиятипов, обнаженных до самого необходимого, чтобы продемонстрировать смысл:
// Validators:
public abstract class Validator<T> { }
public class RequiredValidator<T> : Validator<T> { }
// Fields:
public abstract class Field { }
public abstract class Field<T> : Field
{
public void AddValidator(Validator<T> validator) =>
Console.WriteLine($"Added validator {validator.GetType()}");
}
public sealed class ValueField<T> : Field<T> { }
public sealed class ComputedField<T> : Field<T> { }
...many other field types that inherit Field<T>
Это пример использования свободного интерфейса, которого я хочу достичь:
ValueField<string> field1 = new ValueField<string>().Required();
Метод Required()
должен быть доступен на всех типах, которые наследуют Field<T>
.
Вот что я придумал:
public static class Extensions
{
public static TField Required<TField, T>(this TField field) where TField : Field<T>
{
field.AddValidator(new RequiredValidator<T>());
return field;
}
public static TField DynamicRequired<TField>(this TField field) where TField : Field
{
DynamicAddRequiredValidator((dynamic)field);
return field;
}
private static void DynamicAddRequiredValidator<T>(Field<T> field)
{
field.AddValidator(new RequiredValidator<T>());
}
}
void Main()
{
// This is desired API usage but results in error:
// The type arguments for method 'Extensions.Required<TField,T>(TField)' cannot be inferred from the usage.
ValueField<string> field1 = new ValueField<string>().Required();
// This works but the user shouldn't have to specify types like this, makes it very annoying to use:
ValueField<string> field2 = new ValueField<string>().Required<ValueField<string>, string>();
// This works but requires dynamic:
ValueField<string> field3 = new ValueField<string>().DynamicRequired();
}
Мне не хватает способа достижения этого, который избегает использования dynamic
на основе кода?