--- lang: ja-jp breaks: true --- # `DataContractSerializer` `DataContractResolver` を実装してジェネリック型をシリアライズ/デシリアライズする 2022-02-16 > - [Windows Communication Foundation (WCF) のサンプル](https://docs.microsoft.com/ja-jp/dotnet/framework/wcf/samples/) > [DataContractResolver - WCF | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/framework/wcf/samples/datacontractresolver) ```csharp= // Used at serialization // Maps any Type to a new xsi:type representation public override void ResolveType(Type dataContractType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) { string name = dataContractType.Name; string namesp = dataContractType.Namespace; typeName = new XmlDictionaryString(XmlDictionary.Empty, name, 0); typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, namesp, 0); if (!dictionary.ContainsKey(dataContractType.Name)) { dictionary.Add(name, typeName); } if (!dictionary.ContainsKey(dataContractType.Namespace)) { dictionary.Add(namesp, typeNamespace); } } ``` :::info 上記のサンプルの場合、`string name = dataContractType.Name;`としているため、独自のジェネリックパラメータをデシリアライズすることが出来ない。`string name = dataContractType.FullName;`で対応する必要がある。 ::: ```csharp= public class KnownTypesResolver : DataContractResolver { private Dictionary<string/* typeNamespace + . + typeName */, Type> m_dicTypes = new Dictionary<string, Type>(); private HashSet<string> m_hasAssemblyFullname = new HashSet<string>(); public KnownTypesResolver( Type[] types ) { foreach (Type type in types) { Assembly assembly = type.Assembly; if (m_hasAssemblyFullname.Contains(assembly.FullName) == false) { m_hasAssemblyFullname.Add(assembly.FullName); Type[] allTypes = assembly.GetTypes(); foreach (Type typeFromAssembly in allTypes) { AddType(typeFromAssembly); } } // 指定した型自体も登録しておく。 AddType(type); } } private void AddType(Type type) { string namespace_name = GetDicTypesKey(type); if (m_dicTypes.ContainsKey(namespace_name) == false) { m_dicTypes.Add(namespace_name, type); } } public override Type ResolveName( string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver ) { Type type = null; string namespace_name = GetDicTypesKey(typeNamespace, typeName); m_dicTypes.TryGetValue(namespace_name, out type); return type; } public override bool TryResolveType( Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace ) { string name = GetName(type); string namesp = GetNamespace(type); typeName = new XmlDictionaryString(XmlDictionary.Empty, name , 0); typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, namesp, 0); return true; } private string GetDicTypesKey(string typeNamespace, string typeName) { string namespace_name = typeNamespace + "." + typeName; return namespace_name; } private string GetDicTypesKey(Type type) { return GetDicTypesKey( GetNamespace(type), GetName(type) ); } private const string DefaultNamespace = "global"; internal static string GetNamespace(Type type) { return type?.Namespace ?? DefaultNamespace; } internal static string GetName(Type type) { string name = type?.FullName; // FullNameから、「Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxx」 // 部分を削り、バージョン違いによるエラーを抑止する。 name = reg_FullName.Replace(name, @"${hedad}${tail}"); return name; } #warning 正規表現を使用しているので、速度対応が必要!! private readonly static Regex reg_FullName = new Regex( @"(?<hedad>\[[^\[\], ]+), [^\[\]]+(?<tail>\])", RegexOptions.IgnoreCase | RegexOptions.Compiled ); } ``` ###### tags: `DataContractSerializer` `DataContractResolver` `デシリアライズ` `C#`