Pergunta

I have a class

class Test 
{
    public string SomeValue { get; set; }
    public Func<int, string> DoStuff { get; set; }
}

Which I then instantiate like the following

Test t = new Test();
t.SomeValue = "Your number: ";
t.DoStuff = (n) => { return t.SomeValue + n.ToString(); }; 

After this I tried to store t in RavenDB

RavenSession.Store(t);
RavenSession.SaveChanges(); // This fails

As mentioned in the comment above, RavenSession.SaveChanges() fails with the message

Raven.Imports.Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'extension' with type 'ExampleProject.Test. Path 'DoStuff.target0'.

However, when I serialize the object using Json.NET like this

string s = Newtonsoft.Json.JsonConvert.SerializeObject(t);

the object gets serialized just fine, without an error.

Do I have to configure the RavenDB session differently? (I use all defaults)

I've already tried adding [JsonObject(IsReference = true)] to the class Test, which doesn't help.

Foi útil?

Solução

Delegates cannot be serialized, as they do not contain data but code (well, the delegate type contains some data, but that's not really of any use here). What you're looking to do would be considered marshalling.

After deserialization, your closure will no longer be valid:

Test t = new Test();
t.SomeValue = "Your number: ";
t.DoStuff = (n) => { return t.SomeValue + n.ToString(); };

var deserialized = JsonConvert.Deserialize<Test>(JsonConvert.Serialize(t));
var yourNumber = deserialized.DoStuff(1); // What the heck happens here??

However, I can't even get Func to serialize at all with Json.Net as it doesn't implement ISerializable properly:

class FuncTest
{
    public Func<int, string> DoStuff { get; set; }
    public string Value { get; set; }
}

[Test]
public void Test_Func()
{
    var test = new FuncTest();
    test.DoStuff = (num) => num.ToString();

    var deserialized = JsonConvert.DeserializeObject<FuncTest>(JsonConvert.SerializeObject(test));
    deserialized.Value = deserialized.DoStuff(5);

    Assert.That(deserialized.Value == "5");
}

Newtonsoft.Json.JsonSerializationException : ISerializable type 'System.Func`2[System.Int32,System.String]' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.

In any event, you should not expect the value of your delegate to remain after deserialization. I would use the [JsonIgnore] attribute on the delegate to ensure consistent behavior across Json.Net configurations.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top