Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基类序列化问题-不序列化派生类属性_C#_.net_Json.net - Fatal编程技术网

C# 基类序列化问题-不序列化派生类属性

C# 基类序列化问题-不序列化派生类属性,c#,.net,json.net,C#,.net,Json.net,我已经厌倦了序列化一个相当大的实体列表,这些实体都是从基类派生的。 我只需要客户端中的基类属性。如何在不实例化基类的新实例的情况下实现这一点 我曾尝试创建一个自定义ContractResolver,但它似乎在运行时执行getType(),而不是使用正在序列化的列表/数组的类型 请参阅下面的代码示例 我想要实现。castBaseString==actualBaseString 所以我希望castBaseString=[{“Id”:1},{“Id”:2}]而不是[{“Value”:“Value”,“

我已经厌倦了序列化一个相当大的实体列表,这些实体都是从基类派生的。 我只需要客户端中的基类属性。如何在不实例化基类的新实例的情况下实现这一点

我曾尝试创建一个自定义ContractResolver,但它似乎在运行时执行getType(),而不是使用正在序列化的列表/数组的类型

请参阅下面的代码示例

我想要实现。castBaseString==actualBaseString

所以我希望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);
        }
    }
}
使用System.Linq;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用System.Collections.Generic;
使用Newtonsoft.Json;
命名空间测试{
[测试类]
公共类JSONNETSET{
阶级基础{
公共int Id{get;set;}
}
派生类:基{
公共字符串值{get;set;}
}
类:基{
公共字符串值{get;set;}
公共字符串OtherValue{get;set;}
}
[测试方法]
公开无效测试(){
IEnumerable-deriveds=新派生[]{
新派生的{Id=1,Value=“Value”},
新派生的{Id=2,Value=“value2”}
};
IEnumerable castBases=deriveds.Cast().ToList();
IEnumerable Base=新基[]{
新基{Id=1},
新基{Id=2}
};
JsonSerializerSettings s=新的JsonSerializerSettings();
var derString=JsonConvert.SerializeObject(deriveds,s);
var castBaseString=JsonConvert.SerializeObject(castBases,s);
var actualBaseString=JsonConvert.SerializeObject(基数,s);
AreEqual(actualBaseString、castBaseString);
arenetQual(castBaseString、derString);
}
}
}
根据评论进行编辑 附加上下文:
为了清晰起见,我刚刚发布了这个简单的测试用例。 实际使用的上下文是在aspnet核心应用程序中

假设有3个控制器

  • /api/控制器/
  • /api/OtherDerivedController/
  • /api/BaseController/
  • 当客户端调用1时,我们希望在客户端调用时返回一个派生列表 2我们想返回一个OtherDerived的列表当他们调用3时,我们想返回一个Base的列表

    数据存储在数据库TBL_-DERIVED和TBL_-OTHERDERIVED中的两个不同表中

    当他们调用base时,我们想要实现的是从这些表中的一个或两个返回数据,但只返回这些表的公共属性


    希望这能澄清。

    添加
    [JsonIgnore]
    属性顶部

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

    如果不想使用属性,可以使用ContractResolver强制仅序列化
    Base
    中的属性:

    public类派生的TypeFilterContractResolver:DefaultContractResolver{
    受保护的重写JsonProperty CreateProperty(MemberInfo成员、MemberSerialization MemberSerialization){
    JsonProperty属性=base.CreateProperty(成员,成员序列化);
    if(property.DeclaringType!=typeof(T)){
    property.ShouldSerialize=instance=>false;
    }
    归还财产;
    }
    }
    
    然后像这样使用它:

    void Main(){
    IEnumerable-deriveds=新派生[]{
    新派生的{Id=1,Value=“Value”},
    新派生的{Id=2,Value=“value2”}
    };
    IEnumerable castBases=deriveds.Cast().ToList();
    IEnumerable Base=新基[]{
    新基{Id=1},
    新基{Id=2}
    };
    JsonSerializerSettings s=新的JsonSerializerSettings{
    ContractResolver=新的DerivedTypeFilterContractResolver()
    };
    var derString=JsonConvert.SerializeObject(deriveds,s);
    var castBaseString=JsonConvert.SerializeObject(castBases,s);
    var actualBaseString=JsonConvert.SerializeObject(基数,s);
    Console.WriteLine(castBaseString);
    }
    阶级基础{
    公共int Id{get;set;}
    }
    派生类:基{
    公共字符串值{get;set;}
    }
    
    输出:

    [{“Id”:1},{“Id”:2}]
    
    结果表明,json序列化的工作方式不可能做到这一点。
    @stuartd answer可能是一个很好的解决方法,如果您只想处理有限的情况。

    另一个选项是使用
    [JsonObject(MemberSerialization=MemberSerialization.OptIn)]为
    派生的
    类添加属性,默认情况下排除所有属性(无需使用
    jsoninoreattribute标记它们)。对于其他特定调用,我确实希望序列化该值,但在序列化基类时不这样做。此外,由于它是第三方数据模型,因此我没有向正在使用的类型添加属性的选项。这一切都很好,但现在第二个断言失败,因为在序列化派生时,它将它们序列化为“[{“Id”:1},{“Id”:2}]”,省略派生的.Value字段。另外,如果您现在序列化任何其他不是从Base派生的对象,那么它们都将是“[{},{}]”好的,是的。只有当您只需要基类值时,才可以使用此解析器。有没有关于如何在aspnet核心项目中实现这一点的想法。我非常确定契约解析器在启动时被缓存,并且由于性能原因,您不能在运行时更改它。我会看看这样的东西是否有效:关于如何在aspnet核心项目中做到这一点,有什么想法吗你必须提供更多的细节。您问我,我正在尝试序列化一个相当大的实体列表,这些实体都是从基类派生的。我只需要客户端中的基类属性。使用这个契约解析器就可以做到这一点。但现在你是说你只想这么做