[英]F# “Code is not sufficiently generic” “^T could not be generalized” when implementing interface
我正在嘗試從項目中的Giraffe.Serialization.Json實現IJsonSerializer以使用Microsoft.FSharpLu.Json,但是我遇到了一個泛型方法的問題(下面的代碼)
type FSharpLuSerializer () =
interface Giraffe.Serialization.Json.IJsonSerializer with
member __.Deserialize<'T> (json : string) =
Microsoft.FSharpLu.Json.Default.deserialize<'T> json
我收到了錯誤
此代碼不夠通用。 類型變量^ T無法一般化,因為它會逃避其范圍
我已經看到了同樣錯誤的其他問題,但我不確定如何將他們的解決方案應用於我的情況。 我想它與使用^ T的FSharpLu.Json有關,但我不知道我的解決方法是什么
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>
當我遇到同樣的問題時,我碰到了這個。 我剛剛寫了這篇文章,它似乎正在發揮作用。 我將通過更多步驟來運行它,如果它很好,我會推出一個可以插入的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#人們的反饋也受到歡迎。
跳到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)
非常感謝Nino Floris(@ninofloris)提出這個建議。
這是一個混亂的,一般來說,接口需要捕獲通過泛型在方法上應用的類型,使事情復雜化,你的FSharpLu.Json庫使用內聯SRTP,SRTP內聯模板對^約束類型的方法調用調用所以在編譯的代碼中,每個調用都有一個concreate,fixed類型的方法,這與.net中用於在運行時解析類型的常規reified通用不同。
由於無法內聯接口,請嘗試在接口上添加類型約束,以捕獲類型並避免泛化問題。
type IJsonSerializer<'T> =
abstract member SerializeToString : 'T -> string
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.