简体   繁体   English

基本 Class 序列化问题 - 不序列化派生 Class 属性

[英]Base Class Serialization Issue - do not serialize Derived Class Properties

I am tiring to serialize a fairly large list of entities, that are all derived from a base class.我厌倦了序列化相当大的实体列表,这些实体都是从基础 class 派生的。 I only need the base class properties in the client.我只需要客户端中的基本 class 属性。 How do I achieve this without instantiating a new instance of the base class?如何在不实例化基础 class 的新实例的情况下实现此目的?

I have tried creating a custom ContractResolver, but it seems that it does a getType() at runtime, instead of using the Type of the list/Array being serialized我曾尝试创建一个自定义 ContractResolver,但它似乎在运行时执行 getType(),而不是使用正在序列化的列表/数组的类型

See code sample below.请参阅下面的代码示例。

I want to achieve.我想达到。 castBaseString == actualBaseString; castBaseString == 实际BaseString;

So I want castBaseString to = [{"Id":1},{"Id":2}] not [{"Value":"value","Id":1},{"Value":"value2","Id":2}]所以我希望 castBaseString = [{"Id":1},{"Id":2}]而不是[{"Value":"value","Id":1},{"Value":"value2","Id":2}]

using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Newtonsoft.Json;


namespace Tests {

    [TestClass]
    public class JsonNetTest {
        class Base {
            public int Id { get; set; }
        }

        class Derived : Base {
            public string Value { get; set; }
        }
        
        class OtherDerived : Base {
            public string Value { get; set; }
            public string OtherValue { get; set; }
        }

        [TestMethod]
        public void Test() {
            IEnumerable<Derived> deriveds = new Derived[] {
                new Derived {Id = 1, Value = "value" },
                new Derived {Id = 2, Value = "value2" }
            };

            IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();

            IEnumerable<Base> bases = new Base[] {
                new Base {Id = 1 },
                new Base {Id = 2 }
            };
            JsonSerializerSettings s = new JsonSerializerSettings();

            var derString = JsonConvert.SerializeObject(deriveds, s);
            var castBaseString = JsonConvert.SerializeObject(castBases, s);
            var actualBaseString = JsonConvert.SerializeObject(bases, s);

            Assert.AreEqual(actualBaseString, castBaseString);
            Assert.AreNotEqual(castBaseString, derString);
        }
    }
}

EDIT BASED ON COMMENTS Additional Context:根据评论编辑附加上下文:
I just posted this simple test case for clarity.为了清楚起见,我只是发布了这个简单的测试用例。 the actual context this is being used is in an aspnet core application.正在使用的实际上下文是在 aspnet 核心应用程序中。

Consider there are 3 controllers考虑有 3 个控制器

  1. /api/DerivedController/ /api/派生控制器/
  2. /api/OtherDerivedController/ /api/OtherDerivedController/
  3. /api/BaseController/ /api/基础控制器/

when a client calls 1, we want to return a list of Derived , when a client calls 2 we want to return a list of OtherDerived when they call 3, we want to return a list of Base当客户端调用 1 时,我们想要返回Derived列表,当客户端调用 2 时,我们想要返回OtherDerived列表 当他们调用 3 时,我们想要返回Base列表

The data is stored in 2 different tables in the database TBL_DERIVED and TBL_OTHERDERIVED.数据存储在数据库 TBL_DERIVED 和 TBL_OTHERDERIVED 中的 2 个不同的表中。

What we want to achieve when they call base is to return data from One or both of these tables, but just the common properties of these tables.当他们调用 base 时,我们想要实现的是从这些表中的一个或两个返回数据,而只是这些表的公共属性。

Hope this clarifies.希望这可以澄清。

If you don't want to use attributes, you can use a ContractResolver to force only properties from Base to be serialized:如果您不想使用属性,可以使用 ContractResolver 强制仅对Base中的属性进行序列化:

public class DerivedTypeFilterContractResolver<T> : DefaultContractResolver {
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (property.DeclaringType != typeof(T)) {
            property.ShouldSerialize = instance => false;
        }
        
        return property;
    }
}

Then use it like this:然后像这样使用它:

void Main() {

    IEnumerable<Derived> deriveds = new Derived[] {
                new Derived {Id = 1, Value = "value" },
                new Derived {Id = 2, Value = "value2" }
            };

    IEnumerable<Base> castBases = deriveds.Cast<Base>().ToList();

    IEnumerable<Base> bases = new Base[] {
                new Base {Id = 1 },
                new Base {Id = 2 }
            };

    JsonSerializerSettings s = new JsonSerializerSettings {
        ContractResolver = new DerivedTypeFilterContractResolver<Base>()
    };

    var derString = JsonConvert.SerializeObject(deriveds, s);
    var castBaseString = JsonConvert.SerializeObject(castBases, s);
    var actualBaseString = JsonConvert.SerializeObject(bases, s);

    Console.WriteLine(castBaseString);
}


class Base {
    public int Id { get; set; }
}

class Derived : Base {
    public string Value { get; set; }
}

Output: Output:

[{"Id":1},{"Id":2}]

Add [JsonIgnore] top of property.添加[JsonIgnore]属性顶部。

class Derived : Base {
    [JsonIgnore]
    public string Value { get; set; }
}

Turns out this is not possible the way the json serialization works.事实证明,json 序列化的工作方式是不可能的。 @stuartd answer might be a good workaround if you only have limited cases you want to do this for. @stuartd 答案可能是一个很好的解决方法,如果您只有有限的情况想要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM