views:

318

answers:

1

I have a f# library with some values that I want to serialize in c# with json. With registers I had no problems but I'm having errors when I try to serialize algebraic data types.

For example, lets say this is the f# module and I want to serialize t1.

module Module1=

    type Tree = Leaf  | Branch of Tree * int * Tree

    let t1 = Leaf

In c# I do the following:

DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Module1.Tree));
StreamWriter writer = new StreamWriter(@"c:\test");
serializer.WriteObject(writer.BaseStream, Module1.t1);
writer.Close();

I'm having this error(in spanish because my visual studio is in spanish :S )

"No se espera el tipo 'ns.Module1+Tree+_Leaf' con el nombre de contrato de datos 'Module1.Tree._Leaf:http://schemas.datacontract.org/2004/07/ns'. Agregue los tipos no conocidos estáticamente a la lista de tipos conocidos (por ejemplo, usando el atributo KnownTypeAttribute o agregándolos a la lista de tipos conocidos que se pasa a DataContractSerializer)."

my translation: "The type 'ns.Module1+Tree+_Leaf' was not expected with the data contract name 'Module1.Tree._Leaf:http://schemas.datacontract.org/2004/07/ns'. Add the unknown types statically to the list of known types (for example, using the attribute KnownTypeAttribute or adding them to the list of known types that are passed to DataContractSerializer)."

Any ideas how to solve it?

+3  A: 

The problem is that, from the CLR perspective, the object referenced by t1 is not actually of type Module1.Tree but rather of an unrelated, nested type Module1.Tree+_Leaf. You need to inform the DataContractJsonSerializer that it may encounter objects of this type. Hopefully there is a helper method somewhere in the F# runtime to list such compiler-generated nested types; if not, you'll have to use reflection, e.g.

var serializer = new DataContractJsonSerializer (
    new List<Type> (typeof (Module1.Tree).GetNestedTypes ()) { // nested types
                    typeof (Module1.Tree),                     // root type
    }.ToArray ()) ;

although I'd be a bit scared to write such code unless F# actually specifies exactly how it generates CLR types from algebraic types.

Anton Tykhyy
thanks, that helped me solve that particular error, now I have a new one :P
hiena
Or you can apply `[<KnownType>]` attribute to type `Tree`, as the error message hinted.
Pavel Minaev