首页 文章

是否可以在F#中实现IDbSet <T>接口?

提问于
浏览
9

我试图做一个IDbSet<T>的模拟实现,我碰巧在F#中做了 .

type MockDbSet<'T when 'T : not struct>(items:seq<'T>) =
    let collection = ResizeArray(items)

    new () = MockDbSet(Seq.empty)

    interface IDbSet<'T> with
        member x.Add entity = collection.Add entity; entity
        member x.Attach entity = collection.Add entity; entity
        member x.Remove entity = collection.Remove entity |> ignore; entity
        member x.Create() = Unchecked.defaultof<'T>
        member x.Create<'TD when 'TD : not struct and 'TD :> 'T>() = Unchecked.defaultof<'TD>
        member x.Find([<ParamArray>] values) = raise <| NotImplementedException()
        member x.Local = Collections.ObjectModel.ObservableCollection(collection)

    interface System.Collections.Generic.IEnumerable<'T> with
        member x.GetEnumerator() = 
            collection.GetEnumerator() :> System.Collections.Generic.IEnumerator<_>

    interface System.Collections.IEnumerable with
        member x.GetEnumerator() =
            collection.GetEnumerator() :> System.Collections.IEnumerator

    interface IQueryable<'T> with
        member x.ElementType = typeof<'T>
        member x.Expression =
            collection.AsQueryable().Expression
        member x.Provider =
            collection.AsQueryable().Provider

一切都很好,除了这一行:

member x.Create<'TD when 'TD : not struct and 'TD :> 'T>() = Unchecked.defaultof<'TD>

...这给了我这些编译错误:

错误FS0698:无效约束:用于约束的类型是密封的,这意味着约束只能通过最多一个解决方案警告FS0064来满足:此构造使代码不像类型注释所指示的那样通用 . 类型变量'TD已被约束为类型''T' . 错误FS0663:此类型参数的使用方式限制它始终为'T时'T:not struct'错误FS0661:此绑定的一个或多个显式类或函数类型变量无法一般化,因为他们被限制在其他类型

此行正在尝试实现this method,根据该页面在C#中具有以下签名:

TDerivedEntity Create<TDerivedEntity>()
where TDerivedEntity : class, TEntity

而这个签名在F#中:

abstract Create : unit -> 'TDerivedEntity  when 'TDerivedEntity : not struct and 'TEntity

当我尝试使用示例F#签名时,我得到了各种语法错误,这并不让我感到惊讶,因为该签名甚至看起来不像有效的F# .

我不确定如何处理这些错误消息,或者如何编写我的约束以满足接口和F#编译器 . 我开始怀疑是否有可能在这种特定的Microsoft编程语言中实现这个特定的Microsoft接口 . 任何建议都会受到欢迎 .

2 回答

  • 2

    方法 Create 需要2个泛型类型参数之间的子类型约束 . 我总是假设'm afraid there is no way to add a subtype constraint to a generic type parameter based on another one in F#. They'是相等的,请参阅spec表单类型的新约束:> 'b are solved again as type = ' b .

    看到这个相关的answer类似的问题 .

    我们应该要求在下一个F#版本中包含this功能 .

  • 8

    起初我对此非常失望 . 我仍然在某些方面,但EF6有一个解决方法 . 您可以直接继承 DbSet<'TEntity> ,并使用覆盖在内存中实现集合 . 这对大多数情况来说就足够了;如果你想要 Find 的具体实现,你可以继承这种类型 .

    type FakeDbSet<'TEntity when 'TEntity : not struct>(items: seq<'TEntity>) =
        inherit DbSet<'TEntity>()
        let data = ObservableCollection<'TEntity>(items)
        let query = data.AsQueryable()
        new() = FakeDbSet(Seq.empty)
        override __.Add(item: 'TEntity) = data.Add(item); item
        override __.Remove(item: 'TEntity) = data.Remove(item) |> ignore; item
        override __.Attach(item: 'TEntity) = data.Add(item); item
        override __.Create() = Activator.CreateInstance<'TEntity>()
        override __.Local with get() = data
        interface System.Collections.Generic.IEnumerable<'TEntity> with
            member __.GetEnumerator() = data.GetEnumerator() :> System.Collections.Generic.IEnumerator<_>
        interface System.Collections.IEnumerable with
            member __.GetEnumerator() = data.GetEnumerator() :> System.Collections.IEnumerator
        interface IQueryable<'TEntity> with
            member __.ElementType = typeof<'TEntity>
            member __.Expression = query.Expression
            member __.Provider = query.Provider
    

相关问题