How to serialize a Func<int, int> (or even a general delegate) type field with DataContract/DataMember in WCF

冷暖自知 提交于 2020-06-13 19:32:25

问题


I am trying to serialize a Func<int, int> field marked with [DataMember], of a class marked with [DataContract], whose target or Lambda expression definition is also part of the contract or could even be in the class itself.

I am using a custom DataContractResolver which works perfectly well when I unmark the Func field but when I mark it, it does not resolve a System.DelegateSerializationHolder type needed for the serialization. I tried to add this type to my custom DataContractResolver but I can't find it in the System namespace.

I could redefine it in the [OnDeserialized] method of each client class that uses this class but then I would need to do this every time I use this class, which of course I would like to avoid (client classes are also part of the DataContract).

This serialization is used for the time being for saving the state of the app to disk, so saving delegates (or even events which I am not interested in) makes logical sense as it is all part of the object graph.

So how can I serialize this Func<int, int> using WCF's DataContract?


回答1:


The problem is that it's not possible to use the default WCF serializer for this - delegate serialization will only ever work for .NET.

The solution is to use NetDataContractSerializer instead. In your case, with a persistence context (or File context):

var context = new StreamingContext(StreamingContextStates.Persistence);
var s = new System.Runtime.Serialization.NetDataContractSerializer();

var sb = new StringBuilder();

using (var writer = new XmlTextWriter(new StringWriter(sb)))
{      
    s.WriteObject(writer, new Test() { SomeFunc = (int i) => "Hi".Dump().Length });
}

sb.ToString().Dump();

[DataContract]
class Test
{
    [DataMember]
    public Func<int, int> SomeFunc;
}

Do note that the serializer will only maintain the information about the delegate - that's fine if you're only using compile-time methods for your delegates, but it will not work for dynamically compiled methods. Be warned.

It would also be a good idea to avoid anonymous functions - while they will work, they might also change between different builds, causing your persisted state to become invalid, possibly with disastrous side-effects. Don't forget, the delegate is serialized by method+class name (and return type, and arguments...) - when the name changes, the persisted delegate will point to the new method with the old name. Even with non-anonymous methods, try to make sure you never change the methods that might have been persisted as delegates - ideally, using the original method signature to provide backwards-compatible behaviour, if necessary.

If you ever find yourself adding support for network serialization, just add more StreamingContextStates.



来源:https://stackoverflow.com/questions/30234324/how-to-serialize-a-funcint-int-or-even-a-general-delegate-type-field-with-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!