如何在WCF中使用DataContract / DataMember序列化Func <int,int =“”>(或甚至是一般委托)类型字段

时间:2015-05-14 09:56:29

标签: c# wcf serialization

我正在尝试序列化标有make的{​​{1}}字段,该字段标有Func<int, int>,其目标或Lambda表达式定义也是合同的一部分,甚至可能是在课堂上。

我正在使用自定义[DataMember],当我取消标记[DataContract]字段时,它非常有效,但是当我标记它时,它不会解析序列化所需的DataContractResolver类型。我尝试将此类型添加到我的自定义Func,但我无法在系统命名空间中找到它。

我可以在每个使用这个类的客户端类的System.DelegateSerializationHolder方法中重新定义它,但是每次我使用这个类时我都需要这样做,当然我想避免(客户端类是也是DataContractResolver)的一部分。

此序列化暂时用于将应用程序的状态保存到磁盘,因此保存委托(甚至是我不感兴趣的事件)具有逻辑意义,因为它是对象图的所有部分。

那么如何使用WCF&#39; [OnDeserialized]来序列化DataContract

2 个答案:

答案 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)}");
    }
}