c# - 通用类型层次结构的流畅接口(interface)

标签 c# .net generics fluent

我相信这是实现我想要的目标的唯一方法,但我想把它放在那里看看是否有一个不需要使用动态/反射的解决方案。

我有以下类型层次结构,只保留最基本的内容来演示这一点:

// 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 来实现此目的的方法基于代码?

最佳答案

C# 中的泛型要么全有,要么全无。你要么全部通过,就像你已经做过的那样,要么全部通过。它的设计方式必须使得所有参数都可以推断出来。对于您正在做的事情,您可以使用 Field<T>而不是TField<T> ,删除该泛型类型参数;尽管它可能并不那么理想。还有其他方法...一些 FLUENT 设计返回包含泛型作为属性的新类型,允许您继续前进,但您的延续也需要使用该继续类型的逻辑。这有点令人困惑,但我觉得你明白。如果没有请告诉我。

如果where就好了约束也可以帮助推断类型,但事实并非如此。 Eric Lippert 最近帮助我了解 C# 尝试仅推断通用参数,如果无法推断,则会失败。 where约束只是将泛型类型限制为基类并通知开发人员。虽然感觉我们也可以根据约束进行推断,但因为我们是基于类型的,而 C# 却不然。埃里克(Eric)对不这样做有自己的看法,我确信这超出了我对 ATM 的理解。不管怎样,你已经拥有了。

关于c# - 通用类型层次结构的流畅接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53683564/

相关文章:

c# - 碰撞检测自定义草图形状,表示为点列表

c# - 如何在 C# 中使 winforms 进度条垂直移动?

c# - .NET 属性生成 "must declare a body because it is not marked abstract or extern"编译错误

C# P/调用结构对齐

c# - 在 C# 中更新多维字节数组

Java if 三元运算符和 Collections.emptyList()

.net - 按名称选择特定打印机 VB

.net - "Fluent Assertions"和 "Should Assertion Library"之间的差异

java - 类型删除和对象的 .equals() 方法在通用方法中返回意外结果

entity-framework - .CreateObjectSet<T>、.Set<T> 和 .CreateQuery<T> 之间的区别?