Context:
I am trying to create a couple classes to encapsulate SQL commands in way that fits better with functional programming than the standard System.Data
classes.
There are 3 main types of SQL commands that I care about,
- commands that return nothing
- commands that return 1 row
- commands that return many rows
The implementation for how these must be executed is slightly different, but I want them to all share a common contract, which is why I am using class inheritance. I could also use an interface, but it doesn't seem like a big difference in this case.
I have implemented the shared contract as this base class:
[<AbstractClass>]
type ClosedCommand<'a>(text, kind, parameters) =
inherit OpenCommand(text, kind, parameters)
abstract member execute : cn:IDbConnection -> 'a
And the 3 sub-classes as:
type UnitCommand(text, kind, parameters) =
inherit ClosedCommand<unit>(text, kind, parameters)
override x.execute cn =
let cmd = x.toCommandDefinition null
SqlMapper.Execute(cn, cmd) |> ignore
type SingleCommand<'a>(text, kind, parameters) =
inherit ClosedCommand<'a>(text, kind, parameters)
override x.execute cn =
let cmd = x.toCommandDefinition null
SqlMapper.QuerySingle<'a>(cn, cmd)
type PluralCommand<'a>(text, kind, parameters) =
inherit ClosedCommand<seq<'a>>(text, kind, parameters)
override x.execute cn =
let cmd = x.toCommandDefinition null
SqlMapper.Query<'a>(cn, cmd)
The core of the implementation is the SqlMapper
class from the Dapper library.
Problem:
I am getting a compilation error on the subclass for commands returning nothing. Here is a screenshot:
The message is:
The member execute : IDbConnection -> unit
does not have the correct type to override the corresponding abstract method.
It looks to me like it does have the correct type. Even if I add type annotations, it still gives the same error.
The only difference between this case and the other two is that it is binding unit
to 'a
, whereas the other two leave it generic. That doesn't seem like it should matter.
Minimal example:
[<AbstractClass>]
type CommandBase<'a>(name) =
member this.Name : string = name
abstract member Execute : unit -> 'a
type UnitCommand(name) =
inherit CommandBase<unit>(name)
override this.Execute () = ()
type SingleCommand<'a>(name, x) =
inherit CommandBase<'a>(name)
override this.Execute () = x
type MultipleCommand<'a>(name, xs) =
inherit CommandBase<seq<'a>>(name)
override this.Execute () = xs
How can I get this to compile?