Dies kann mit einem benutzerdefinierten IContractResolver
, durch die Verlängerung eines der bereits bestehenden Resolvern erstellt erfolgen, zum Beispiel DefaultContractResolver
:
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class LegacyDataMemberNamesAttribute : Attribute
{
public LegacyDataMemberNamesAttribute() : this(new string[0]) { }
public LegacyDataMemberNamesAttribute(params string[] names)
{
this.Names = names;
}
public string [] Names { get; set; }
}
public class LegacyPropertyResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
static LegacyPropertyResolver instance;
static LegacyPropertyResolver() { instance = new LegacyPropertyResolver(); }
public static LegacyPropertyResolver Instance { get { return instance; } }
protected LegacyPropertyResolver() : base() { }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
for (int i = 0, n = properties.Count; i < n; i++)
{
var property = properties[i];
if (!property.Writable)
continue;
var attrs = property.AttributeProvider.GetAttributes(typeof(LegacyDataMemberNamesAttribute), true);
if (attrs == null || attrs.Count == 0)
continue;
// Little kludgy here: use MemberwiseClone to clone the JsonProperty.
var clone = property.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var name in attrs.Cast<LegacyDataMemberNamesAttribute>().SelectMany(a => a.Names))
{
if (properties.Any(p => p.PropertyName == name))
{
Debug.WriteLine("Duplicate LegacyDataMemberNamesAttribute: " + name);
continue;
}
var newProperty = (JsonProperty)clone.Invoke(property, new object[0]);
newProperty.Readable = false;
newProperty.PropertyName = name;
properties.Add(newProperty);
}
}
return properties;
}
}
Beachten Sie, dass diese Implementierung erfordert nicht, dass die Klasse explizite Daten Vertragsattribut Annotation . Sie können diese Einschränkung hinzufügen, wenn Sie bevorzugen.
verwenden Sie es dann mit der folgenden JsonSerializerSettings
:
var settings = new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance };
Zum Beispiel:
[DataContract]
class TestObject
{
[LegacyDataMemberNames("alpha", "omega")]
[DataMember(Name = "a")]
public int A { get; set; }
}
public static class JsonExtensions
{
public static void RenameProperty(this JObject obj, string oldName, string newName)
{
if (obj == null)
throw new NullReferenceException();
var property = obj.Property(oldName);
if (property != null)
{
property.Replace(new JProperty(newName, property.Value));
}
}
}
public class TestClass
{
public static void Test()
{
try
{
TestInner();
}
catch (Exception ex)
{
Debug.Assert(false, ex.ToString()); // No assert
throw;
}
}
public static void TestInner()
{
var test = new TestObject { A = 42 };
var settings = new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance };
var json = JObject.FromObject(test, JsonSerializer.CreateDefault(settings));
if (json.SelectToken("alpha") != null || json.SelectToken("omega") != null)
throw new InvalidOperationException("Failed serialization");
Test(test, json);
json.RenameProperty("a", "alpha");
Test(test, json);
json.RenameProperty("alpha", "omega");
Test(test, json);
}
private static void Test(TestObject test, JObject json)
{
var test1 = json.ToObject<TestObject>(JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = LegacyPropertyResolver.Instance }));
if (test1.A != test.A)
throw new InvalidOperationException("Failed deserialization");
Console.WriteLine("Successfully deserialized: " + json.ToString(Formatting.None));
Debug.WriteLine("Successfully deserialized: " + json.ToString(Formatting.None));
}
}
Mein Gott, wow, das ist eine unglaublich gründliche Antwort. Vielen Dank. – bboyle1234