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