问题
I'm working on code that abstracts away System.Data.IDbConnection
and its siblings.
target code
let inline runWithConnection connector f =
match connector with
| ICon con -> f con
| CString cs ->
use conn = new SqlConnection(cs)
openConnection conn
f conn
I can see that type constraints compile and run, but constraining to object doesn't have the intended effect. I want to constrain to an object or value that is not a function that needs more inputs to return something. Alternatively write this in such a way that if it does return a function the possibly created connection isn't closed until f is done with it.
let inline runWithConnection connector (f:_ -> 't when 't :> obj) =
match connector with
| ICon con -> f con
| CString cs ->
use conn = new SqlConnection(cs)
openConnection conn
f conn
It seems you can say 't : not struct
but you can't say 't: not delegate
I thought about doing f.GetType()
but then I have no idea which type properties like .IsClass
, .IsAbstract
, .IsValue
would be consistent with delegate types as opposed to other simple types. Also that would be run-time instead of compile time, not really improving the situation.
回答1:
I think what you're saying that this doesn't work when you call runWithConnection
with a curried f
as the connection is disposed after the first partial function is returned.
No generic constraints will solve this as you can't constrain to a type that isn't something i.e. a function. This is the same across F#, C#, Java etc.
You could possibly throw a runtime exception, but I think it's much easier to revisit the pattern you're attempting. I'd ask what you save by having the outer function execute the function it's passed, rather than just returning the generated connection as an IDisposable
. This would let the calling function control the scope of the connection, e.g.:
use conn = getConnection myConnector
doSomethingWithConnection conn anotherArg
回答2:
Note that your problem isn't limited to just function return types - there are plenty of "normal" types that problematic, too. Consider if f
is (fun conn -> [conn])
- then you're just returning a list, but the connection stored in that list will be closed by the time the function returns. Likewise, you could create a class type ConnectionUser
whose constructor takes and stores a connection and whose methods/properties use it, and that wouldn't work as a return type for f
for the same reason. So I agree with Tim Rogers that you should try to come up with a cleaner abstraction.
As an aside, I don't think that inline
is buying you anything here, so you can probably safely drop it.
来源:https://stackoverflow.com/questions/35462215/how-would-i-constrain-to-non-function