首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在不调用构造函数的情况下反序列化类?

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

Stack Overflow用户
提问于 2012-12-19 16:10:37
回答 3查看 9.5K关注 0票数 18

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

下面是我的类(简化):

代码语言:javascript
复制
[DataContract]
public class Component
{
    public Component()
    {
        // I'm doing some magic here.
    }
}

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

如果不清楚,很抱歉,请随时提问。

EN

回答 3

Stack Overflow用户

发布于 2012-12-19 16:14:18

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

代码语言:javascript
复制
[DataContract]
public class Component
{
    // for JSON.NET
    protected Component()
    {
    }

    public Component(allMandatoryFieldsHere)
    {
        // I'm doing some magic here.
    }
}

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

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

因此,使用FormatterServices.GetSafeUninitializedObject是一种丑陋的变通办法,因为没有人知道您是以未初始化的方式创建所有对象的。构造函数初始化的存在是有原因的。更好的做法是,类可以通过提供我建议的“序列化”构造函数来告知不调用真正的构造函数是可以的。

票数 11
EN

Stack Overflow用户

发布于 2016-08-26 03:34:10

其他人已经提到了第二个构造函数,但使用两个属性: JsonConstructor和Obsolete,你可以做得更好,而不是让人类去记住调用哪个构造函数。

代码语言:javascript
复制
    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仍然可以调用它,因为它是通过反射来实现的。

票数 2
EN

Stack Overflow用户

发布于 2014-01-22 17:15:58

避免在反序列化时调用构造函数的最佳选择是创建特殊的协定解析器,它覆盖所有没有标记有JsonConstructor属性的构造函数的类的创建者函数。通过这种方式,如果你真的需要,你仍然可以强制JSON.NET调用构造函数,但是所有其他的类都会像.NET中的标准DataContract序列化程序一样被创建。代码如下:

代码语言:javascript
复制
/// <summary>
/// Special contract resolver to create objects bypassing constructor call.
/// </summary>
public class NoConstructorCreationContractResolver : DefaultContractResolver
{
    /// <summary>
    /// Creates a <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type.
    /// </summary>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>
    /// A <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type.
    /// </returns>
    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<JsonProperty, bool> 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, i.e. 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;
    }
}

您只需在反序列化之前在序列化程序设置中设置此协定解析器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13947997

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档