使用Json.net仅将接口属性序列化为JSON

eka*_*808 31 c# serialization json.net

使用像这样的简单类/接口

public interface IThing
{
    string Name { get; set; }
}

public class Thing : IThing
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如何只使用"Name"属性(仅底层接口的属性)获取JSON字符串?

实际上,当我做到这一点时:

var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
Run Code Online (Sandbox Code Playgroud)

我得到完整的对象为JSON(Id + Name);

小智 25

我用的方法,

public class InterfaceContractResolver : DefaultContractResolver
{
    private readonly Type _InterfaceType;
    public InterfaceContractResolver (Type InterfaceType)
    {
        _InterfaceType = InterfaceType;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        //IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
        return properties;
    }
}

// To serialize do this:
var settings = new JsonSerializerSettings() {
     ContractResolver = new InterfaceContractResolver (typeof(IThing))
});
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Run Code Online (Sandbox Code Playgroud)


ras*_*asx 19

灵感来自@ user3161686,这是一个小修改InterfaceContractResolver:

public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
        return properties;
    }
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*ver 16

带有嵌套接口的改进版本+支持xsd.exe对象

这里还有另一种变化.代码来自http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html,其中的其他答案有以下改进

  • 处理层次结构,因此如果你有一个Interface2[],Interface1那么它将被序列化.
  • 我试图序列化一个WCF代理对象,结果JSON出现了{}.原来所有的属性都被设置为Ignore=true所以我不得不添加一个循环来将它们全部设置为不被忽略.

    public class InterfaceContractResolver : DefaultContractResolver
    {
        private readonly Type[] _interfaceTypes;
    
        private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
    
        public InterfaceContractResolver(params Type[] interfaceTypes)
        {
            _interfaceTypes = interfaceTypes;
    
            _typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
        }
    
        protected override IList<JsonProperty> CreateProperties(
            Type type,
            MemberSerialization memberSerialization)
        {
            var typeToSerialize = _typeToSerializeMap.GetOrAdd(
                type,
                t => _interfaceTypes.FirstOrDefault(
                    it => it.IsAssignableFrom(t)) ?? t);
    
            var props = base.CreateProperties(typeToSerialize, memberSerialization);
    
            // mark all props as not ignored
            foreach (var prop in props)
            {
                prop.Ignored = false;
            }
    
            return props;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)


Nik*_*off 12

您可以使用条件序列化.看看这个链接.基本上,您需要实现IContractResolver接口,重载ShouldSerialize方法并将解析器传递给Json Serializer的构造函数.


Mar*_*eur 8

[JsonIgnore][DataContract][DataMember]属性的替代方案.如果您使用[DataContract]序列化程序标记了类,则只处理使用该[DataMember]属性标记的属性("op-in" JsonIgnore是"选择退出"模型DataContract).

[DataContract]
public class Thing : IThing
{
    [DataMember]
    public int Id { get; set; }

    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这两种方法的局限在于它们必须在类中实现,不能将它们添加到接口定义中.


小智 6

您可以添加[JsonIgnore]注释以忽略属性.

  • 这可以在没有属性的情况下定义这些忽略吗?实际上,我也无法修改界面或类. (4认同)