You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何序列化Delegate类型属性?DataContractSerializer序列化报错求助

问题描述

尝试用DataContractSerializer将Delegate序列化到XML文件时,抛出第一个异常:

System.Runtime.Serialization.SerializationException : Type 'System.DelegateSerializationHolder+DelegateEntry' with data contract name 'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.

编写自定义DataContractResolver后,又触发第二个异常:

System.ArgumentException : Invalid name character in '<>c'. The '<' character, hexadecimal value 0x3C, cannot be included in a name.

自定义Resolver代码如下:

public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver,
            out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
    var name = type.Name;
    var nameSpace = type.Namespace;

    typeName = new XmlDictionaryString(XmlDictionary.Empty, name, 0);
    if (nameSpace != null)
    {
        typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, nameSpace, 0);

        if (!dictionary.ContainsKey(type.Name)) dictionary.Add(name, typeName);

        if (type.Namespace != null && !dictionary.ContainsKey(type.Namespace))
            dictionary.Add(nameSpace, typeNamespace);

        return true;
    }

    typeName = null;
    typeNamespace = null;
    return false;
}

疑问:

  1. 自定义Resolver哪里出错了?怎么修复?
  2. 还有其他序列化Delegate的方法吗?

解决方案

自定义Resolver的问题分析

  1. 非法字符报错原因:你直接使用type.Name作为XML元素名,但Delegate关联的闭包类型(编译器自动生成的<>c这类名称)包含<>等XML命名禁止的特殊字符,违反XML规范。
  2. 逻辑缺陷:Resolver没有针对性处理Delegate相关的系统内部类型(比如DelegateSerializationHolder.DelegateEntry),反而对所有类型返回自定义名称,扩大了问题范围。

修复后的Delegate专用Resolver

public class DelegateDataContractResolver : DataContractResolver
{
    private readonly Dictionary<string, Type> _typeMap = new Dictionary<string, Type>();
    private readonly XmlDictionary _xmlDict = new XmlDictionary();

    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, 
        out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
    {
        // 只处理Delegate类型或系统内部的Delegate包装类型
        if (typeof(Delegate).IsAssignableFrom(type) || type.FullName == "System.DelegateSerializationHolder+DelegateEntry")
        {
            // 清理XML非法字符,替换为下划线
            string safeTypeName = Regex.Replace(type.Name, @"[^\w\-.]", "_");
            string safeNamespace = type.Namespace ?? "http://schemas.datacontract.org/2004/07/System";

            typeName = _xmlDict.Add(safeTypeName);
            typeNamespace = _xmlDict.Add(safeNamespace);

            if (!_typeMap.ContainsKey(safeTypeName))
                _typeMap.Add(safeTypeName, type);

            return true;
        }

        // 其他类型交给默认解析器处理
        return knownTypeResolver.TryResolveType(type, declaredType, knownTypeResolver, out typeName, out typeNamespace);
    }

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
    {
        // 反序列化时根据映射找回类型
        if (_typeMap.TryGetValue(typeName, out Type targetType))
            return targetType;

        return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, knownTypeResolver);
    }
}

使用方式

初始化序列化器时传入该Resolver:

var serializer = new DataContractSerializer(
    typeof(YourContainingType), 
    null, 
    int.MaxValue, 
    false, 
    true, 
    null, 
    new DelegateDataContractResolver()
);

其他序列化Delegate的方案

  1. BinaryFormatter:对Delegate序列化支持完善,直接调用即可,但官方标记为过时,仅建议在可信环境使用。
  2. 手动序列化关键信息:不直接序列化Delegate实例,而是序列化其目标类型、方法名,反序列化时重建Delegate:
    // 序列化逻辑
    public void WriteDelegate(XmlWriter writer, Delegate del)
    {
        writer.WriteElementString("TargetType", del.Target?.GetType().AssemblyQualifiedName);
        writer.WriteElementString("MethodName", del.Method.Name);
    }
    
    // 反序列化逻辑
    public Delegate ReadDelegate(XmlReader reader, Type delegateType)
    {
        string targetTypeStr = reader.ReadElementString("TargetType");
        string methodName = reader.ReadElementString("MethodName");
    
        Type targetType = Type.GetType(targetTypeStr);
        MethodInfo method = targetType.GetMethod(methodName);
    
        return Delegate.CreateDelegate(delegateType, null, method);
    }
    
  3. Newtonsoft.Json:JSON格式下对Delegate序列化支持较好,默认即可处理,或手动序列化方法元数据。

内容的提问来源于stack exchange,提问作者Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 09:05:29