---
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#`