sdgfsdh
sdgfsdh

Reputation: 37045

How do I implement this generic C# interface using F#?

I want to create an object with this interface in F#:

namespace JWT
{
    /// <summary>
    /// Provides JSON Serialize and Deserialize.  Allows custom serializers used.
    /// </summary>
    public interface IJsonSerializer
    {
        /// <summary>
        /// Serialize an object to JSON string
        /// </summary>
        /// <param name="obj">object</param>
        /// <returns>JSON string</returns>
        string Serialize(object obj);

        /// <summary>
        /// Deserialize a JSON string to typed object.
        /// </summary>
        /// <typeparam name="T">type of object</typeparam>
        /// <param name="json">JSON string</param>
        /// <returns>Strongly-typed object</returns>
        T Deserialize<T>(string json);
    }
}

I have tried using an object expression but the generic Deserialize method is tripping me up:

  let serializer =
    {
      new JWT.IJsonSerializer
        with
          member this.Serialize (o : obj) =
            failwith "Not implemented"

          member this.Deserialize (json : string) =
            let decoded : Result<'t, string> = 
              Decode.fromString payloadDecoder json

            match decoded with
            | Result.Ok (o : 't) ->
              o
            | Result.Error error ->
              failwith error
    }

The error is:

This code is not sufficiently generic. The type variable 'a could not be generalized because it would escape its scope

How can I implement this?


$ dotnet --version
3.1.300

Upvotes: 3

Views: 156

Answers (1)

pim
pim

Reputation: 12577

We can deal with this error by annotating the member. This way the type system will have enough information to fully discern what is going on.

If I tweak your code slightly, I'm able to get it to compile:

open Thoth.Json

type IJsonSerializer =
  abstract member Serialize : o:obj -> string
  abstract member Deserialize<'a> : json:string -> 'a

type Json () =
    let payloadDecoder : Decoder<'a> = 
        fun _ -> failwith "not impl."

    interface IJsonSerializer with
        member this.Serialize (o : obj) : string =
            failwith "not impl."

        member this.Deserialize<'a> (json : string) : 'a =
            match Decode.fromString payloadDecoder json with
            | Ok (o : 'a) -> o
            | Error error -> failwith error

By fully annotating the Deserialize member the type system should now be satisfied.

A couple things to note:

  • I included an F# version of the IJsonSerializer interface so my code could compile. Though it's not necessary for your final result.
  • I included a stub for the payloadDecoder since you did not include it in your question. So even though this code will compile, it will not actually work.

Upvotes: 0

Related Questions