问题
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