如何在不调用构造函数的情况下反序列化类?

我在我的WCF数据服务中使用Json.NET。

这是我的课程(简化):

[DataContract] public class Component { public Component() { // I'm doing some magic here. } } 

如何在使用JsonConvert.DeserializeObject调用构造函数的情况下反序列化该类?

对不起,如果不清楚,随时提问。

  1. 您可以创建一个inheritance自CustomCreationConverter的类,并使用FormatterServices.GetSafeUninitializedObject来创建您的对象。 它会跳过调用构造函数。

    有关CustomCreationConverter的更多信息,请点击此处 。

  2. 在类上放置[JsonObject(MemberSerialization.Fields)]将使Json.NET默认使用FormatterServices.GetSafeUninitializedObject (尽管Fields模式也将序列化公共/私有字段,而不是您可能不需要的公共属性)。

  3. 移动您不希望在默认构造函数之外运行的逻辑。

始终调用构造函数。 我通常有两个构造函数。 一个用于序列化(默认构造函数),一个用于所有“常规”代码:

 [DataContract] public class Component { // for JSON.NET protected Component() { } public Component(allMandatoryFieldsHere) { // I'm doing some magic here. } } 

通过这种方式,我还可以确保开发人员指定所需的所有信息。

但是,我并不建议您在传输信息时使用除DTO之外的任何东西,因为否则可能会绕过对象的封装(任何人都可以使用任何值初始化任何字段)。 好。 如果你使用任何东西,但贫血模型。

因此,使用FormatterServices.GetSafeUninitializedObject是一个丑陋的解决方法,因为没有人可以告诉你以非实体方式创建所有对象。 构造函数初始化是有原因的。 通过提供我建议的“序列化”构造函数,类可以告诉可以不调用真正的构造函数,这样做会更好。

其他人已经提到了第二个构造函数,但使用了2个属性:[JsonConstructor]和[Obsolete]你可以做得更好,而不是留给人类来记住要调用哪一个。

  public ChatMessage() { MessageID = ApplicationState.GetNextChatMessageID(); // An expensive call that uses up an otherwise free ID from a limited set and does disk access in the process. } [JsonConstructor] // This forces JsonSerializer to call it instead of the default. [Obsolete("Call the default constructor. This is only for JSONserializer", true)] // To make sure that calling this from your code directly will generate a compiler error. JSONserializer can still call it because it does it via reflection. public ChatMessage(bool DO_NOT_CALL_THIS) { } 

[JsonConstructor]强制JsonSerializer调用它而不是默认值。
[Obsolete(“…”,true)]确保直接从代码中调用它会产生编译器错误。 JSONserializer仍然可以调用它,因为它通过reflection来实现。

避免对反序列化进行构造函数调用的最佳选择是创建特殊的契约解析器,该解析器将覆盖所有类的创建函数,而不使用标记有JsonConstructor属性的构造函数。 这样你仍然可以强制JSON.NET调用构造函数,如果你真的需要它,但所有其他类将像.NET中的标准DataContract序列化程序一样创建。 这是代码:

 ///  /// Special contract resolver to create objects bypassing constructor call. ///  public class NoConstructorCreationContractResolver : DefaultContractResolver { ///  /// Creates a  for the given type. ///  /// Type of the object. ///  /// A  for the given type. ///  protected override JsonObjectContract CreateObjectContract(Type objectType) { // prepare contract using default resolver var objectContract = base.CreateObjectContract(objectType); // if type has constructor marked with JsonConstructor attribute or can't be instantiated, return default contract if (objectContract.OverrideConstructor != null || objectContract.CreatedType.IsInterface || objectContract.CreatedType.IsAbstract) return objectContract; // prepare function to check that specified constructor parameter corresponds to non writable property on a type Func isParameterForNonWritableProperty = parameter => { var propertyForParameter = objectContract.Properties.FirstOrDefault(property => property.PropertyName == parameter.PropertyName); if (propertyForParameter == null) return false; return !propertyForParameter.Writable; }; // if type has parameterized constructor and any of constructor parameters corresponds to non writable property, return default contract // this is needed to handle special cases for types that can be initialized only via constructor, ie Tuple<> if (objectContract.ParametrizedConstructor != null && objectContract.ConstructorParameters.Any(parameter => isParameterForNonWritableProperty(parameter))) return objectContract; // override default creation method to create object without constructor call objectContract.DefaultCreatorNonPublic = false; objectContract.DefaultCreator = () => FormatterServices.GetSafeUninitializedObject(objectContract.CreatedType); return objectContract; } } 

您只需在反序列化之前在序列化程序设置中设置此合约解析程序。