Generics 具有两个泛型类型的类中的类型约束不匹配,重载以使两个类型相等

Generics 具有两个泛型类型的类中的类型约束不匹配,重载以使两个类型相等,generics,f#,Generics,F#,我对泛型类型约束有问题 背景:我刚刚开始使用WPF,正在创建一个类来帮助验证。目标是从XAML轻松使用,以及从后端验证中的类型安全 为此,我创建了一个封装另一个值的类。它有一个我在XAML中绑定到的属性Raw,以及一个提供最终、有效和转换结果的属性Valid。该类使用转换器和对转换值的检查列表进行实例化。当然,转换器和检查都可能失败 我想创建两个重载:一个不带检查的重载生成只转换的包装,另一个不带转换器的重载生成只检查不转换的包装。我对后者有意见。以下是INotifyPropertyChange

我对泛型类型约束有问题

背景:我刚刚开始使用WPF,正在创建一个类来帮助验证。目标是从XAML轻松使用,以及从后端验证中的类型安全

为此,我创建了一个封装另一个值的类。它有一个我在XAML中绑定到的属性Raw,以及一个提供最终、有效和转换结果的属性Valid。该类使用转换器和对转换值的检查列表进行实例化。当然,转换器和检查都可能失败

我想创建两个重载:一个不带检查的重载生成只转换的包装,另一个不带转换器的重载生成只检查不转换的包装。我对后者有意见。以下是INotifyPropertyChanged和IDataErrorInfo类:

type Validated<'raw, 'converted>
      (init:'raw,
       convert:'raw->Result<'converted,string>,
       checks:('converted->Result<unit,string>) list) =

  let getValidationError converted validate =
    match validate converted with
    | Ok () -> None
    | Error err -> Some err

  new(init:'raw, convert:'raw->Result<'converted,string>) = 
    Validated(init, convert, [])

  // This is the one I'm having trouble with  
  new(init:'raw, checks:('converted->Result<unit,string>) list) = 
    Validated(init, Ok, checks)

  member val Raw = init with get, set

  member private this.Converted = convert this.Raw

  member this.Errors =
      match this.Converted with
      | Ok x -> checks |> List.choose (getValidationError x)
      | Error x -> [x]

  member this.ValidValue = 
    match this.Converted, this.Errors with
    | Ok x, [] -> Some x
    | _ -> None
在第二个重载中,我得到了以下错误:此构造代码导致代码不像类型注释所指示的那样通用。类型变量“raw”已被约束为“转换类型”。这当然有道理——因为它不转换,所以类型必须相同

是否有可能为此类创建这样的重载,或者我必须使用另一个具有单个类型参数的类


请注意,我可以使用new Validated,Ok,[]创建一个实例,该实例的类型为Validated。这只是我遇到的实际构造函数重载问题。

您试图做的是让您的一个类构造函数构造不同类型类的实例。当然,这是不可能发生的:类的构造函数只能构造该类的实例

如果您想拥有专门的构造函数,只需将其设置为函数之外:

let validatedNoChecks init convert = Validated( init, convert, [] )
let validatedNoConvert init checks = Validated( init, Ok, checks )
还要注意,您的实现有点效率低下:属性主体将在每次访问时运行,而不仅仅是在构建时运行一次

一般来说,我建议不要使用类。它们只出现在F中,以支持与C和其他.NET语言的互操作。它们会产生类似于代码中的问题,并且不会添加任何内容。绝对没有理智的理由使用它们

例如,您的已验证类可以构建为记录+构造函数:

type Validated 'raw 'converted = { raw: 'raw; errors: string list; validValue: 'converted option }

let validated init convert checks =
    let getValidationError converted validate =
        match validate converted with
        | Ok () -> None
        | Error err -> Some err

    let converted = convert init
    let errors = match converted with
        | Ok x -> checks |> List.choose (getValidationError x)
        | Error x -> [x]
    let validValue = match converted, errors with
        | Ok x, [] -> Some x
        | _ -> None

    { raw = init; errors = errors; validValue = validValue }
然后是专业施工人员:

let validatedNoChecks init convert = validated init convert []
let validatedNoConvert init checks = validated init Ok checks
如果您真的需要将面向对象的接口扩展到一些外部C代码,请使用接口:只需将上述记录转换为接口并使用对象表达式构造它即可。仍然没有理由使用类


如果你想对结果进行懒散的评估,那么就使用lazy。你真的需要使用一个类吗?如果你计划使用WPF并进行验证,我建议你考虑一下,谢谢。但是由于这里的用例是从XAML简单绑定到的,所以你的解决方案缺少一些关键的东西。首先,原始值需要是可变的。其次,我需要INotifyPropertyChanged和IDataErrorInfo,以便绑定和验证工作,特别是对于INPC,这可以通过从合适的基类继承轻松完成。总的来说,我不明白你为什么对逃课如此严格。我在viewmodels中很少使用类,我的经验是,在某些情况下,它们是完成这项工作的合适工具。请随意通过解决这些问题来启发我。