我正在尝试序列化标有make
的{{1}}字段,该字段标有Func<int, int>
,其目标或Lambda表达式定义也是合同的一部分,甚至可能是在课堂上。
我正在使用自定义[DataMember]
,当我取消标记[DataContract]
字段时,它非常有效,但是当我标记它时,它不会解析序列化所需的DataContractResolver
类型。我尝试将此类型添加到我的自定义Func
,但我无法在系统命名空间中找到它。
我可以在每个使用这个类的客户端类的System.DelegateSerializationHolder
方法中重新定义它,但是每次我使用这个类时我都需要这样做,当然我想避免(客户端类是也是DataContractResolver
)的一部分。
此序列化暂时用于将应用程序的状态保存到磁盘,因此保存委托(甚至是我不感兴趣的事件)具有逻辑意义,因为它是对象图的所有部分。
那么如何使用WCF&#39; [OnDeserialized]
来序列化DataContract
?
答案 0 :(得分:4)
问题在于,无法使用默认的WCF序列化程序 - 委托序列化只能用于.NET。
解决方案是使用NetDataContractSerializer
代替。在您的情况下,使用持久化上下文(或File
上下文):
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;
}
请注意,序列化程序只会维护有关委托的信息 - 如果你只是为你的代表使用编译时方法,这很好,但它会< em> not 适用于动态编译的方法。警告。
避免匿名函数也是一个好主意 - 当它们将工作时,它们也可能在不同构建之间发生变化,导致持久状态变为无效,可能带来灾难性的副作用。别忘了,委托是按方法+类名(和返回类型,以及参数......)序列化的 - 当名称更改时,持久委托将指向具有旧名称的新方法。即使使用非匿名方法,也要确保永远不要更改可能作为委托持久化的方法 - 理想情况下,如果需要,使用原始方法签名来提供向后兼容的行为。
如果您发现自己添加了对网络序列化的支持,只需添加更多StreamingContextStates
。
答案 1 :(得分:1)
我知道这篇文章已经有几年了。我找到了解决这个问题的方法,我更多地使用了 mikecodes.net 知识。因此,请查看他的网站以获取更多信息。这是我的简化:
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
public static class Script
{
public static Func<int, int> Compile(string code) => CSharpScript.EvaluateAsync<Func<int, int>>(code, ScriptOptions.Default).Result;
}
[Serializable] // DataContract stuff
public class Data
{
public string Code { get; set; }
public string Name { get; set; }
public int Value { get; set; }
private Func<int, int> _func = null;
public Func<int,int> Function
{
get
{
if(_func ==null)
{
_func = Script.Compile(this.Code);
}
return _func;
}
}
}
public class Program
{
public void Main()
{
var data = new Data
{
Code = "i=>i + 1",
Name = "Sample",
Value = 2
};
Console.WriteLine($"Function = {data.Function(data.Value)}");
}
}