Is there a way to ignore get-only properties in Json.NET without using JsonIgnore attributes?

后端 未结 4 1189
不知归路
不知归路 2020-11-29 05:19

Is there a way to ignore get-only properties using the Json.NET serializer but without using JsonIgnore attributes?

For example, I have a class with the

相关标签:
4条回答
  • 2020-11-29 05:29

    Use the OptIn mode of JSON.net and you'll only need to decorate the properties you want to serialize. This isn't as good as automatically opting out all read only properties, but it can save you some work.

    [JsonObject(MemberSerialization.OptIn)]
    public class MyClass
    {
        [JsonProperty]
        public string serializedProp { get; set; }
    
        public string nonSerializedProp { get; set; }
    }
    

    Udate: Added another possibility using reflection

    If the above solution still isn't quite what you're looking for, you could use reflection to make dictionary objects which would then be serialized. Of course the example below will only work for simple classes, so you would need to add recursion if your classes contain other classes. This should at least point you in the right direction.

    The subroutine to put the filtered result into a dictionary:

        private Dictionary<String, object> ConvertToDictionary(object classToSerialize)
        {
            Dictionary<String, object> resultDictionary = new Dictionary<string, object>();
    
            foreach (var propertyInfo in classToSerialize.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (propertyInfo.CanWrite) resultDictionary.Add(propertyInfo.Name, propertyInfo.GetValue(classToSerialize, null));
            }
    
            return resultDictionary;
        }
    

    A snippet showing its use:

    SampleClass sampleClass = new SampleClass();
    sampleClass.Hotkey = Keys.A;
    var toSerialize = ConvertToDictionary(sampleClass);
    String resultText = JsonConvert.SerializeObject(toSerialize);
    
    0 讨论(0)
  • 2020-11-29 05:38

    You can do this by implementing a custom IContractResolver and using that during serialization. If you subclass the DefaultContractResolver, this becomes very easy to do:

    class WritablePropertiesOnlyResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
            return props.Where(p => p.Writable).ToList();
        }
    }
    

    Here is a test program demonstrating how to use it:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;
    
    class Program
    {
        static void Main(string[] args)
        {
            Widget w = new Widget { Id = 2, Name = "Joe Schmoe" };
    
            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                ContractResolver = new WritablePropertiesOnlyResolver()
            };
    
            string json = JsonConvert.SerializeObject(w, settings);
    
            Console.WriteLine(json);
        }
    }
    
    class Widget
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LowerCaseName
        {
            get { return (Name != null ? Name.ToLower() : null); }
        }
    }
    

    Here is the output of the above. Notice that the read-only property LowerCaseName is not included in the output.

    {"Id":2,"Name":"Joe Schmoe"}
    
    0 讨论(0)
  • 2020-11-29 05:45

    Json.net does have the ability to conditionally serialize properties without an attribute or contract resolver. This is especially useful if you don't want your project to have a dependency on Json.net.

    As per the Json.net documentation

    To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.

    0 讨论(0)
  • 2020-11-29 05:47

    You can use a contract resolver like this:

    public class ExcludeCalculatedResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            property.ShouldSerialize = _ => ShouldSerialize(member);
            return property;
        }
    
        internal static bool ShouldSerialize(MemberInfo memberInfo)
        {
            var propertyInfo = memberInfo as PropertyInfo;
            if (propertyInfo == null)
            {
                return false;
            }
    
            if (propertyInfo.SetMethod != null)
            {
                return true;
            }
    
            var getMethod = propertyInfo.GetMethod;
            return Attribute.GetCustomAttribute(getMethod, typeof(CompilerGeneratedAttribute)) != null;
        }
    }
    

    It will exclude calculated properties but include C#6 get only properties and all properties with a set method.

    0 讨论(0)
提交回复
热议问题