So come serializzare in F # utilizzando oggetti mutabili, ma esiste un modo per serializzare/deserializzare utilizzando i tipi di record utilizzando XmlSerializer o DataContractSerializer? sembra che ci sia un modo per farlo per un'unione discriminata usando l'attributo KnownType, ma sto cercando un modo per usare record non mutabili senza costruttore predefinito ...F # Serializzazione dei tipi di record
risposta
L'esempio code for reading data from Freebase di Jomo Fisher usa DataContractJsonSerializer
per carica i dati in record F # immutabili. La dichiarazione del record che usa assomiglia a questo:
[<DataContract>]
type Result<'TResult> = { // '
[<field: DataMember(Name="code") >]
Code:string
[<field: DataMember(Name="result") >]
Result:'TResult // '
[<field: DataMember(Name="message") >]
Message:string }
Il punto chiave qui è che l'attributo il DataMember
è attaccato al campo sottostante che viene effettivamente utilizzato per memorizzare i dati e non alla proprietà di sola lettura che il compilatore F # genera (usando il modificatore field:
sull'attributo).
Io non sono sicuro al 100% se si tratta di andare a lavorare con altri tipi di serializzazione (probabilmente non), ma può essere un puntatore utile per cominciare ...
EDIT Sono non sono sicuro se mi manca qualcosa qui, ma il seguente esempio di base funziona bene per me:
module Demo
#r "System.Runtime.Serialization.dll"
open System.IO
open System.Text
open System.Xml
open System.Runtime.Serialization
type Test =
{ Result : string[]
Title : string }
do
let sb = new StringBuilder()
let value = { Result = [| "Hello"; "World" |]; Title = "Hacking" }
let xmlSerializer = DataContractSerializer(typeof<Test>);
xmlSerializer.WriteObject(new XmlTextWriter(new StringWriter(sb)), value)
let sr = sb.ToString()
printfn "%A" sr
let xmlSerializer = DataContractSerializer(typeof<Test>);
let reader = new XmlTextReader(new StringReader(sr))
let obj = xmlSerializer.ReadObject(reader) :?> Test
printfn "Reading: %A" obj
EDIT 2 Se si desidera generare XML più pulito allora si può aggiungere attributi in questo modo:
[<XmlRoot("test")>]
type Test =
{ [<XmlArrayAttribute("results")>]
[<XmlArrayItem(typeof<string>, ElementName = "string")>]
Result : string[]
[<XmlArrayAttribute("title")>]
Title : string }
questo è un inizio, ma il xml che viene generato non è "pulito", voglio dire che i tag sono come "FSI_0132.Test "invece di Test e Title_x0040_ invece del titolo. Sembra anche che non possa impostare i tag xml sul tipo con attributi come [
Lo spazio dei nomi "FSI_0132" è generato da F # Interactive - nel codice compilato, sarebbe stato sostituito con il tuo spazio dei nomi effettivo Non sono sicuro del nome della proprietà, però. –
@Joel: giusto, lo capisco, ma il mio obiettivo è quello di avere un XML pulito senza alcuna informazione sul namespace, come faresti se provassi a deserializzare usando la classe XmlSerializer in .net – Alex
È possibile utilizzare questa serie di annotazioni sulle proprietà delle classi per formattare l'XML:
[XmlRoot("root")]
[XmlElement("some-element")]
[XmlAttribute("some-attribute")]
[XmlArrayAttribute("collections")]
[XmlArrayItem(typeof(SomeClass), ElementName = "item")]
io uso gli attributi sulle mie classi C#, ma deserializzare in F # (C# le classi sono ina riferimento lib).
in F #:
use file = new FileStream(filePath, FileMode.Open)
let serializer= XmlSerializer(typeof<SomeClass>)
let docs = serializer.Deserialize file :?> SomeClass
che è cool, ma il requisito è quello di utilizzare i tipi non mutabili, quindi questo approccio non funzionerà dato che la classe avrà campi mutabili – Alex
Non usa XmlSerializer o DataContractSerializer, ma Json.NET 6.0 includes nice F# support.
Ecco come si presenta:
type TestTarget =
{ a: string
b: int }
[<TestFixture>]
type JsonTests() =
[<Test>]
member x.``can serialize``() =
let objectUnderTest = { TestTarget.a = "isa"; b = 9 }
let jsonResult: string = Newtonsoft.Json.JsonConvert.SerializeObject(objectUnderTest)
printfn "json is:\n%s" jsonResult
let xmlResult = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonResult, "root")
printfn "xml is:\n%s" (xmlResult.OuterXml)
let jsonRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(jsonResult)
printfn "json roundtrip: %A" jsonRoundtrip
let xmlAsJson = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlResult, Newtonsoft.Json.Formatting.Indented, true)
printfn "object -> json -> xml -> json:\n%A" xmlAsJson
let xmlRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(xmlAsJson)
printfn "xml roundtrip:\n%A" xmlRoundtrip
Assert.That(true, Is.False)
()
json is:
{"a":"isa","b":9}
xml is:
<root><a>isa</a><b>9</b></root>
json roundtrip: {a = "isa";
b = 9;}
object -> json -> xml -> json:
"{
"a": "isa",
"b": "9"
}"
xml roundtrip:
{a = "isa";
b = 9;}
fantastici per mostrare un modo di usare i tipi di record senza bisogno del '[
Ho scoperto che questo non rispettava la distinzione tra maiuscole e minuscole dei nomi dei membri (venivano sempre convertiti in minuscolo). –
che iniziano con F # 3.0, la serializzazione di registrazione i tipi sono ora supportati applicando lo CliMutableAttribute
al tipo. Esempio:
[<CLIMutable>]
type MyRecord = { Name : string; Age : int }
Questo esempio è tratto da http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx, che include una discussione di questa funzione e altre tre nuove funzionalità di F # 3.0: le stringhe triple-citato, proprietà automatiche, e gli avvisi di variabili non utilizzate.
- 1. F #, Json, WebApi Serializzazione dei tipi di opzione
- 2. spiegazione dei tipi scala f
- 3. JSON: serializzazione dei tipi derivati da IEnumerable
- 4. accattivarsi dei 'tipi flessibili' in F #
- 5. strano comportamento di F # record
- 6. Eredita record F #
- 7. Serializzare F # tipi di opzione
- 8. modificatore privato per F tipi #
- 9. Record di modellazione del database come tipi
- 10. Condivisione di tipi su file F # .fsx
- 11. Tipo di raccolta F # per tipi misti
- 12. Haskell: Aggiornamento record per tipi esistenziali
- 13. Perché i tipi flessibili non sono consentiti nelle definizioni dei tipi di record?
- 14. Alias di spazi dei nomi in F #?
- 15. F #, serializzazione di unioni discriminate con valori privi di dati
- 16. Espressione di tipi esistenziali in F #
- 17. I tipi di phantom F # in pratica
- 18. Come fare la convalida degli argomenti di F # record
- 19. Lavorare con i tipi F # in C#
- 20. Haskell che introspecting i nomi dei campi di un record e tipi
- 21. Haskell a F # - dichiara tipi ricorsivi in f #
- 22. Come escludere tipi specifici dalla serializzazione?
- 23. Teoria dei tipi: tipi di tipo
- 24. uguaglianza inferenza in F # record + con campi mutabili
- 25. Trasmissione dinamica di tipi sconosciuti per la serializzazione
- 26. Modellazione dei tipi di dati algebrici tramite database relazionale
- 27. Unità generiche f # su tipi generici
- 28. Entity Framework e anonimi Tipi in F #
- 29. Come trasferiscono i tipi F # a C#?
- 30. Posso usare i tipi dinamici in F #?
ho finito con l'utilizzo dell'analisi in xml, il che è stato altrettanto valido nel mio caso, quello che ho provato non funzionava per produrre xml pulito, anche con i suggerimenti di Tomas per usare gli attributi di System.Xml.Serialization, il mio sospetto era che fosse Non ho intenzione di lavorare, ma ho deciso di provare comunque e loro no, credo perché il namespace del datacontract ignora questi. il mio requisito era quello di utilizzare record non modificabili per questo esercizio, ma se il tuo obiettivo è solo la serializzazione xml, non è diverso dal suo utilizzo in qualsiasi altro linguaggio .net, basta creare classi, decorarle e usare XmlSerializer, funzionerà. – Alex