10

I am using StackExchange.Redis to access a Redis instance.

I have the following working C# code:

public static void Demo()
{
    ConnectionMultiplexer connection = ConnectionMultiplexer.Connect("xxx.redis.cache.windows.net,ssl=true,password=xxx");

    IDatabase cache = connection.GetDatabase();

    cache.StringSet("key1", "value");
}

Here is the what I would hope would be the equivalent F# code:

let Demo() =
   let cx = ConnectionMultiplexer.Connect @"xxx.redis.cache.windows.net,ssl=true,password=xxx"
   let cache = cx.GetDatabase()
   cache.StringSet("key1", "value") |> ignore

However this does not compile - 'No overloads match for method StringSet'. The StringSet method expects arguments of type RedisKey and RedisValue, and there seems to be some compiler magic going on in C# to convert the strings in the calling code into RedisKey and RedisValue. The magic does not appear to exist in F#. Is there a way of achieving the same result?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Kit
  • 2,089
  • 1
  • 11
  • 23
  • Are there `RedisKey.op_Implicit` and `RedisValue.op_Implicit` operators? – Daniel Dec 03 '14 at 15:03
  • @Daniel - looks like it. If I navigate to definition I get the following .fsi generated: type RedisKey = ... static member op_Implicit : key:string -> RedisKey static member op_Implicit : key:byte [] -> RedisKey static member op_Implicit : key:RedisKey -> byte [] static member op_Implicit : key:RedisKey -> string – Kit Dec 03 '14 at 15:05
  • 3
    Then you'll need to do `StringSet(RedisKey.op_Implicit "key1", RedisValue.op_Implicit "value")`. Those are called automatically in C#, but not F#. You can also [define an "implicit" operator](http://stackoverflow.com/a/10720073/162396). – Daniel Dec 03 '14 at 15:08
  • Awesome, looks like this will work. If you post that as an answer I will mark it as such and get you magic interweb points. Thanks! – Kit Dec 03 '14 at 15:12
  • 1
    I would personally extend string to have toRedisKey and toRedisVal funs. More readable, controllable, and clear what's going on. Do same for RedisKey to convert to string or whatever. – Philip P. Dec 05 '14 at 09:39
  • Thanks a lot @Daniel, and thanks a lot Kit for asking – himekami Nov 03 '16 at 14:40

1 Answers1

13

Here is the working code, many thanks to @Daniel:

open StackExchange.Redis
open System.Collections.Generic

let inline (~~) (x:^a) : ^b = ((^a or ^b) : (static member op_Implicit: ^a -> ^b) x)

let Demo() =
   let cx = ConnectionMultiplexer.Connect @"xxx.redis.cache.windows.net,ssl=true,password==xxx"
   let cache = cx.GetDatabase()

   // Setting a value - need to convert both arguments:
   cache.StringSet(~~"key1", ~~"value") |> ignore

   // Getting a value - need to convert argument and result:
   cache.StringGet(~~"key1") |> (~~) |> printfn "%s"
ildjarn
  • 62,044
  • 9
  • 127
  • 211
Kit
  • 2,089
  • 1
  • 11
  • 23
  • I have a similar problem I have a string key and value I want to put it into and get it out of redis let searchToken = RedisKey.op_Implicit ("myKey" + token) let resultValue = cache.StringGet(searchToken) let redisData = RedisValue.op_Implicit(resultValue) When I run this, I get: The type 'RedisValue' does not support a conversion to the type ''a' Not sure what I am doing wrong. How do I tell the RedisValue.op_Implicit that it is indeed a string? – Jamie Dixon Sep 07 '17 at 17:24