Last active
March 3, 2018 17:06
-
-
Save CallumWatkins/2ca41e12b86eb5710af8cccc1cd63857 to your computer and use it in GitHub Desktop.
A Json.NET serialization binder to allow providing a custom type name using an attribute. License: MIT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ========== | |
// Usage: | |
[JsonTypeName("CustomNameHere")] | |
public class Usage | |
{ | |
public string Example { get; set; } = "Hello World"; | |
} | |
// Serialize: | |
JsonConvert.SerializeObject(new Usage(), | |
new JsonSerializerSettings() | |
{ | |
SerializationBinder = new JsonTypeNameSerializationBinder(), | |
TypeNameHandling = TypeNameHandling.All, | |
Formatting = Formatting.Indented | |
}); | |
// Generates: | |
{ | |
"$type": "CustomNameHere", | |
"Example": "Hello World" | |
} | |
// ========== | |
/// <summary> | |
/// Set a custom type name for use during serialization and deserialization with Json.NET. | |
/// </summary> | |
[AttributeUsage(AttributeTargets.Class)] | |
public class JsonTypeNameAttribute : Attribute | |
{ | |
public string TypeName { get; } | |
public JsonTypeNameAttribute(string typeName) | |
{ | |
TypeName = typeName; | |
} | |
} | |
/// <summary> | |
/// A serialization binder for use with the <see cref="JsonTypeNameAttribute"/> on classes in the declared or specified assembly. | |
/// </summary> | |
public class JsonTypeNameSerializationBinder : DefaultSerializationBinder | |
{ | |
private readonly Dictionary<string, Type> _nameToType; | |
private readonly Dictionary<Type, string> _typeToName; | |
public JsonTypeNameSerializationBinder(Assembly assembly = null) | |
{ | |
(Type type, string name)[] customNames = GetCustomTypeNames().ToArray(); | |
_nameToType = customNames.ToDictionary(t => t.name, t => t.type); | |
_typeToName = customNames.ToDictionary(t => t.type, t => t.name); | |
IEnumerable<(Type type, string name)> GetCustomTypeNames() | |
{ | |
foreach (Type type in assembly?.GetTypes() ?? this.GetType().Assembly.GetTypes()) | |
{ | |
foreach (object customAttribute in type.GetCustomAttributes(false)) | |
{ | |
if (customAttribute is JsonTypeNameAttribute jsonTypeNameAttribute) | |
{ | |
yield return (type, jsonTypeNameAttribute.TypeName); | |
break; | |
} | |
} | |
} | |
} | |
} | |
public override void BindToName(Type serializedType, out string assemblyName, out string typeName) | |
{ | |
if (_typeToName.TryGetValue(serializedType, out string name)) | |
{ | |
assemblyName = null; | |
typeName = name; | |
} | |
else | |
{ | |
base.BindToName(serializedType, out assemblyName, out typeName); | |
} | |
} | |
public override Type BindToType(string assemblyName, string typeName) | |
{ | |
if (_nameToType.TryGetValue(typeName, out Type type)) | |
{ | |
return type; | |
} | |
else | |
{ | |
return base.BindToType(assemblyName, typeName); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment