How to deserialize class without calling a constructor?

后端 未结 4 840
长发绾君心
长发绾君心 2021-01-01 16:38

I\'m using Json.NET in my WCF data service.

Here\'s my class (simplified):

[DataContract]
public class Component
{
    public Component()
    {
              


        
4条回答
  •  伪装坚强ぢ
    2021-01-01 16:54

    The best option to avoid constructor calls on deserialization is to create special contract resolver that overrides creator function for all classes without constructor marked with JsonConstructor attribute. This way you still can force JSON.NET to call constructor if you really need it, but all other classes will be created much like in standard DataContract serializers in .NET. Here is the code:

    /// 
    /// 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, 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;
        }
    }
    

    All you need is simply set this contract resolver in serializer settings before deserialization.

提交回复
热议问题