C# 根据条件选择要序列化到的POCO

C# 根据条件选择要序列化到的POCO,c#,json,inheritance,serialization,C#,Json,Inheritance,Serialization,我想根据对象“meta”区域中的字段将json文档中的嵌套对象序列化为POCO(纯旧c#object),但我不知道如何实现 例如,假设我有以下文档: { "id": 123, "type": "beer", "_source": { "name": "myBeer", "brewery": "myBrewery", "address": "blah" } } 使用这种格式,源字段将映射到另一个POCO,其中包含字段名称、酿酒厂和地址 现在,假设我

我想根据对象“meta”区域中的字段将json文档中的嵌套对象序列化为POCO(纯旧c#object),但我不知道如何实现

例如,假设我有以下文档:

{
  "id": 123,
  "type": "beer",
  "_source": {
     "name": "myBeer",
     "brewery": "myBrewery", 
     "address": "blah"
  }
}
使用这种格式,源字段将映射到另一个POCO,其中包含字段名称、酿酒厂和地址

现在,假设我在同一索引中有另一个具有以下字段的文档:

{
  "id": 345,
  "type": "brewery",
  "_source": {
    "name": "mybrewery",
    "date": "somedate", 
    "city": "somecity"
  }
}
因此,基于文档的类型变量,\ u源信息应序列化为不同的POCO


我知道,
ShouldSerialize
方法适用于类中的属性,那么有类似的方法适用于类吗?基本上,这将根据条件将json对象序列化到特定的POCO?

在序列化继承的类型时可以实现这一点。序列化程序将自动向JSON文档添加元属性,这将有助于反序列化为正确的类型。不过,您可能需要调整一些设置才能实现这一点。告诉我们您正在使用的序列化程序,以便有人可以帮助您了解具体情况

但是,无论如何,您不应该这样做。这些元属性特定于所使用的序列化程序。例如,Web API 2的默认JSON序列化程序添加了一个名为“
$type
”的属性,而数据契约JSON序列化程序添加了一个名为“
\uu type
”的属性。这意味着您在JSON提供者和JSON使用者之间引入了紧密耦合——两者都必须使用相同的序列化程序


\u source
创建两种不同的类型:一种用于酿酒厂,另一种用于啤酒。这将为您和每个利益相关者节省大量的麻烦。

您需要存储合同信息,以便从外部元信息中解析正确的类型

编写一个将为您完成全部工作的转换器类:

public class DocConverter
{
    private readonly Dictionary<string, Func<MetaInformation, object>> deserializers = new Dictionary<string, Func<MetaInformation, object>>();
    private readonly Dictionary<Type, Func<object, string>> serializers = new Dictionary<Type, Func<object, string>>();

    private class MetaInformation
    {
        [Newtonsoft.Json.JsonProperty( "id" )]
        public int Id { get; set; }
        [Newtonsoft.Json.JsonProperty( "type" )]
        public string Type { get; set; }
        [Newtonsoft.Json.JsonProperty( "_source" )]
        public object Source { get; set; }
    }

    public void Register<Source, SourceData>( string contractName, Func<Source, Tuple<int,SourceData>> converter, Func<<Tuple<int, SourceData>, Source> reverter )
        where Source : class
        where SourceData : class
    {
        deserializers.Add( contractName,
            ( m ) =>
            {
                SourceData data = Newtonsoft.Json.JsonConvert.DeserializeObject<SourceData>( m.Source.ToString() );
                return reverter( Tuple.Create( m.Id, data ) );                    
            } );

        serializers.Add( typeof( Source ),
            ( o ) =>
            {   
                var data = converter( (Source) o );
                var meta = new MetaInformation { Id = data.Item1, Type = contractName, Source = data.Item2, };
                return Newtonsoft.Json.JsonConvert.SerializeObject( meta );
            } );
    }

    public string Serialize( object source )
    {
        return serializers[ source.GetType() ]( source );
    }

    public object Deserialize( string jsonData )
    {
        var meta = Newtonsoft.Json.JsonConvert.DeserializeObject<MetaInformation>( jsonData );
        return deserializers[ meta.Type ]( meta );
    }
}
真正的阶级

public class Beer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Brewery { get; set; }
    public string Address { get; set; }
}

public class Brewery
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Date { get; set; }
    public string City { get; set; }
}
毕竟,我们只注册合同名称、转换器和还原器

var conv = new DocConverter();
conv.Register<Beer, BeerSource>( 
    "beer", 
    ( o ) => Tuple.Create( o.Id, new BeerSource { Name = o.Name, Brewery = o.Brewery, Address = o.Address, } ), 
    ( t ) => new Beer { Id = t.Item1, Name = t.Item2.Name, Brewery = t.Item2.Brewery, Address = t.Item2.Address, } );
conv.Register<Brewery, BrewerySource>( 
    "brewery", 
    ( o ) => Tuple.Create( o.Id, new BrewerySource { Name = o.Name, Date = o.Date, City = o.City, } ), 
    ( t ) => new Brewery { Id = t.Item1, Name = t.Item2.Name, Date = t.Item2.Date, City = t.Item2.City, } );
var conv = new DocConverter();
conv.Register<Beer, BeerSource>( 
    "beer", 
    ( o ) => Tuple.Create( o.Id, new BeerSource { Name = o.Name, Brewery = o.Brewery, Address = o.Address, } ), 
    ( t ) => new Beer { Id = t.Item1, Name = t.Item2.Name, Brewery = t.Item2.Brewery, Address = t.Item2.Address, } );
conv.Register<Brewery, BrewerySource>( 
    "brewery", 
    ( o ) => Tuple.Create( o.Id, new BrewerySource { Name = o.Name, Date = o.Date, City = o.City, } ), 
    ( t ) => new Brewery { Id = t.Item1, Name = t.Item2.Name, Date = t.Item2.Date, City = t.Item2.City, } );
object source;
object result;
string jsonData;

source = new Beer { Id = 123, Name = "myBeer", Brewery = "myBrewery", Address = "blah", };
jsonData = conv.Serialize( source );
// check the JSON result
Console.WriteLine( jsonData );
result = conv.Deserialize( jsonData );
// check the result type
Console.WriteLine( result.GetType().ToString() );

source = new Brewery { Id = 456, Name = "myBrewery", Date = "somedate", City = "somecity", };
jsonData = conv.Serialize( source );
// check the JSON result
Console.WriteLine( jsonData );
result = conv.Deserialize( jsonData );
// check the result type
Console.WriteLine( result.GetType().ToString() );