F # «Код недостаточно универсален» «^ T не может быть обобщен» при реализации интерфейса - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь реализовать IJsonSerializer от Giraffe.Serialization.Json в проекте для использования Microsoft.FSharpLu.Json, но у меня возникают проблемы с одним из общих методов (код ниже)

type FSharpLuSerializer () =
    interface Giraffe.Serialization.Json.IJsonSerializer with
        member __.Deserialize<'T> (json : string) =
            Microsoft.FSharpLu.Json.Default.deserialize<'T> json

Мне выдается ошибка

Этот код недостаточно универсален.Переменная типа ^ T не может быть обобщена, поскольку она выйдет за рамки

Я видел другие вопросы с той же ошибкой, но я не уверен, как применить их решения в моей ситуации.Я предполагаю, что это как-то связано с FSharpLu.Json, использующим ^ T, но я не знаю, каким будет мой обходной путь

https://github.com/Microsoft/fsharplu/blob/master/FSharpLu.Json/Default.fs

Вот интерфейс Giraffe IJSonSerializer

[<AllowNullLiteral>]
type IJsonSerializer =
    abstract member SerializeToString<'T>      : 'T -> string
    abstract member SerializeToBytes<'T>       : 'T -> byte array
    abstract member SerializeToStreamAsync<'T> : 'T -> Stream -> Task

    abstract member Deserialize<'T>      : string -> 'T
    abstract member Deserialize<'T>      : byte[] -> 'T
    abstract member DeserializeAsync<'T> : Stream -> Task<'T>

Ответы [ 3 ]

0 голосов
/ 23 февраля 2019

Я столкнулся с этим, когда столкнулся с той же проблемой.Я только что написал это, и это, кажется, работает.Я прогоню его еще через несколько шагов, и, если это будет хорошо, я выложу пакет NuGet, куда его можно подключить.

open Giraffe.Serialization
open Microsoft.FSharpLu.Json
open Newtonsoft.Json
open System.IO
open System.Text
open System.Threading.Tasks

type FSharpLuJsonSerializer() =
  interface IJsonSerializer with
    member __.SerializeToString<'T>      (x : 'T) =
      Compact.serialize x
    member __.SerializeToBytes<'T>       (x : 'T) =
      Text.Encoding.UTF8.GetBytes (Compact.serialize x)
    member __.SerializeToStreamAsync<'T> (x : 'T) (stream : Stream) =
      let serializer = new JsonSerializer()
      serializer.Converters.Add (CompactUnionJsonConverter ())
      use sw = new StreamWriter (stream)
      use writer = new JsonTextWriter (sw)
      serializer.Serialize (writer, obj)
      Task.CompletedTask

    member __.Deserialize<'T> (json : string) =
      (Compact.deserialize >> box) json :?> 'T
    member __.Deserialize<'T> (bytes : byte[]) =
      (Compact.deserialize >> box) (Encoding.UTF8.GetString (ReadOnlySpan bytes)) :?> 'T
    member __.DeserializeAsync<'T> (stream : Stream) =
      Task.FromResult<'T> ((Compact.deserializeStream >> box) stream :?> 'T)

Также приветствуются отзывы от F #.

0 голосов
/ 23 февраля 2019

После прыжка на F # Slack есть еще более простой способ сделать это, не требуя всего бокса и кастинга.FSharpLu использует Newtonsoft.Json под капотом, и его компактная функциональность происходит от типа CompactUnionJsonConverter.Вы можете добавить этот конвертер к стандартному Giraffe JsonSerializerSettings, и он работает - это означает, что вам не нужно полностью переопределять IJsonSerializer.

  open Giraffe.Serialization
  open Microsoft.FSharpLu.Json
  open Newtonsoft.Json

  let jsonSettings = 
    let x = NewtonsoftJsonSerializer.DefaultSettings
    x.Converters.Add (CompactUnionJsonConverter (true))
    x

Затем, где вы конфигурируете свои службы ...

    services.AddSingleton<IJsonSerializer>(NewtonsoftJsonSerializer jsonSettings)

Огромное спасибо Нино Флорису (@ninofloris) за это предложение.

0 голосов
/ 15 декабря 2018

это беспорядок, в общем, интерфейсы должны захватывать тип, который будет применен с помощью обобщенных методов, чтобы еще больше усложнить ситуацию, ваша библиотека FSharpLu.Json использует встроенные SRTP, встроенный шаблон SRTP, вызов вызова метода на^ тип ограничения, так что в скомпилированном коде есть конкретный метод фиксированного типа для каждого вызова, он отличается от обычных обобщенных обобщенных символов, используемых в .net, которые разрешают тип во время выполнения.

Поскольку вы не можете встроитьинтерфейс, попробуйте добавить ограничение типа на интерфейс, который будет перехватывать тип и избегать проблемы обобщения.

type IJsonSerializer<'T> =
abstract member SerializeToString      : 'T -> string
...
...