我正在尝试对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:此构造导致代码更少 通用而不是类型注释。类型变量&#39; TD 被限制为类型&#39; T&#39;。
错误FS0663:此类型 参数的使用方式将其限制为始终为&#39; T. 当&t; T:不结构&#39;
错误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接口。任何建议都会受到欢迎。
答案 0 :(得分:8)
方法Create
需要2个泛型类型参数之间的子类型约束。我担心没有办法根据F#中的另一个参数向泛型类型参数添加子类型约束。它们总是被假定为相等,请参阅表单类型的spec 新约束:&gt; 'b再次被解决为type ='b。
请参阅此相关问题answer。
我们应该要求在下一个F#版本中加入this功能。
答案 1 :(得分:2)
起初我对此感到非常失望。我仍然在某些方面,但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