C# 是否可以使用.NET DataContractJSONSerializer对JSON文件进行反序列化,该文件的格式与通常序列化的格式不同?

C# 是否可以使用.NET DataContractJSONSerializer对JSON文件进行反序列化,该文件的格式与通常序列化的格式不同?,c#,json,datacontractjsonserializer,C#,Json,Datacontractjsonserializer,我有一个JSON文件,格式如下,由一个我无法编辑的工具生成: { "thing_name1": { "property1": 0, "property2": "sure" }, "thing_name2": { "property1": 34, "property2": "absolutely" } } 我试图反序列化到的类如下所示: [DataContract] public class Thin

我有一个JSON文件,格式如下,由一个我无法编辑的工具生成:

{
    "thing_name1": {
        "property1": 0,
        "property2": "sure"
    },
    "thing_name2": {
        "property1": 34,
        "property2": "absolutely"
    }
}
我试图反序列化到的类如下所示:

[DataContract]
public class Thing
{
    [DataMember]
    public String ThingName;

    [DataMember(Name="property1")]
    public int Property1;

    [DataMember(Name="property2")]
    public String Property2;
}

我需要将“thing_name1”和“thing_name2”的值放入它们各自反序列化对象的ThingName数据成员中,但如果不编写自定义(反)序列化程序,就无法找到一种简单的方法来实现这一点。或者编写一个快速Python脚本来编写另一个文件,但这并不是很节省空间。

是的,这是可能的,但您确实需要一些自定义代码来完成

这有点难看,但是您可以创建一个自定义类来将JSON反序列化到
字典中,然后将嵌套字典结构中的值复制到
列表中。以下是代理所需的代码:

class MyDataContractSurrogate : IDataContractSurrogate
{
    public Type GetDataContractType(Type type)
    {
        if (type == typeof(List<Thing>))
        {
            return typeof(Dictionary<string, Dictionary<string, object>>);
        }
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        if (obj.GetType() == typeof(Dictionary<string, Dictionary<string, object>>) &&
            targetType == typeof(List<Thing>))
        {
            List<Thing> list = new List<Thing>();

            foreach (var kvp in (Dictionary<string, Dictionary<string, object>>)obj)
            {
                Thing thing = new Thing { ThingName = kvp.Key };
                Dictionary<string, object> propsDict = kvp.Value;

                foreach (PropertyInfo prop in GetDataMemberProperties(typeof(Thing)))
                {
                    DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>();

                    object value;
                    if (propsDict.TryGetValue(att.Name, out value))
                    {
                        prop.SetValue(thing, value);
                    }
                }
                list.Add(thing);
            }

            return list;
        }
        return obj;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (obj.GetType() == typeof(List<Thing>) &&
            targetType == typeof(Dictionary<string, Dictionary<string, object>>))
        {
            var thingsDict = new Dictionary<string, Dictionary<string, object>>();

            foreach (Thing thing in (List<Thing>)obj)
            {
                var propsDict = new Dictionary<string, object>();
                foreach (PropertyInfo prop in GetDataMemberProperties(typeof(Thing)))
                {
                    DataMemberAttribute att = prop.GetCustomAttribute<DataMemberAttribute>();
                    propsDict.Add(att.Name, prop.GetValue(thing));
                }
                thingsDict.Add(thing.ThingName, propsDict);
            }

            return thingsDict;
        }
        return obj;
    }

    private IEnumerable<PropertyInfo> GetDataMemberProperties(Type type)
    {
        return type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetCustomAttribute<DataMemberAttribute>() != null);
    }

    // ------- The rest of these methods are not needed -------
    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
    {
        throw new NotImplementedException();
    }

    public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
    {
        throw new NotImplementedException();
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        throw new NotImplementedException();
    }

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
    {
        throw new NotImplementedException();
    }
}
请注意,在
Thing
类中,不应使用
[DataMember]
属性标记
ThingName
成员,因为它是在代理中专门处理的。另外,我假设您的类成员实际上是属性(使用
{get;set;}
),而不是您在问题中编写的字段。如果该假设不正确,则需要将代理代码中对
PropertyInfo
的所有引用更改为使用
FieldInfo
;否则代理将不起作用

[DataContract]
public class Thing
{
    // Don't mark this property with [DataMember]
    public string ThingName { get; set; }

    [DataMember(Name = "property1")]
    public int Property1 { get; set; }

    [DataMember(Name = "property2")]
    public string Property2 { get; set; }
}
下面是一个往返演示:

public class Program
{
    public static void Main(string[] args)
    {
        string json = @"
        {
          ""thing_name1"": {
            ""property1"": 0,
            ""property2"": ""sure""
          },
          ""thing_name2"": {
            ""property1"": 34,
            ""property2"": ""absolutely""
          }
        }";

        var settings = new DataContractJsonSerializerSettings();
        settings.DataContractSurrogate = new MyDataContractSurrogate();
        settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) };
        settings.UseSimpleDictionaryFormat = true;

        List<Thing> things = Deserialize<List<Thing>>(json, settings);

        foreach (Thing thing in things)
        {
            Console.WriteLine("ThingName: " + thing.ThingName);
            Console.WriteLine("Property1: " + thing.Property1);
            Console.WriteLine("Property2: " + thing.Property2);
            Console.WriteLine();
        }

        json = Serialize(things, settings);
        Console.WriteLine(json);
    }

    public static T Deserialize<T>(string json, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            var ser = new DataContractJsonSerializer(typeof(T), settings);
            return (T)ser.ReadObject(ms);
        }
    }

    public static string Serialize(object obj, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            var ser = new DataContractJsonSerializer(obj.GetType(), settings);
            ser.WriteObject(ms, obj);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }
}

您是直接使用
DataContractJsonSerializer
,还是使用内部调用它的WCF?您的JSON无效:有一个额外的外部
{}
。上载到,您将看到一个错误。这是你真正的JSON吗?如果没有,你能分享吗?我直接使用DataContractJsonSerializer。对帖子中的JSON错误表示歉意,该错误已被修复。我不能分享实际使用的JSON,但是如果一个解决方案能够使用所提供的内容,那么它应该与我的工具一起使用。谢谢,这非常有效!最后,我不得不为我拥有的一个列表属性添加一点内容,但就问题而言,这正是我想要的。
public class Program
{
    public static void Main(string[] args)
    {
        string json = @"
        {
          ""thing_name1"": {
            ""property1"": 0,
            ""property2"": ""sure""
          },
          ""thing_name2"": {
            ""property1"": 34,
            ""property2"": ""absolutely""
          }
        }";

        var settings = new DataContractJsonSerializerSettings();
        settings.DataContractSurrogate = new MyDataContractSurrogate();
        settings.KnownTypes = new List<Type> { typeof(Dictionary<string, Dictionary<string, object>>) };
        settings.UseSimpleDictionaryFormat = true;

        List<Thing> things = Deserialize<List<Thing>>(json, settings);

        foreach (Thing thing in things)
        {
            Console.WriteLine("ThingName: " + thing.ThingName);
            Console.WriteLine("Property1: " + thing.Property1);
            Console.WriteLine("Property2: " + thing.Property2);
            Console.WriteLine();
        }

        json = Serialize(things, settings);
        Console.WriteLine(json);
    }

    public static T Deserialize<T>(string json, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        {
            var ser = new DataContractJsonSerializer(typeof(T), settings);
            return (T)ser.ReadObject(ms);
        }
    }

    public static string Serialize(object obj, DataContractJsonSerializerSettings settings)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            var ser = new DataContractJsonSerializer(obj.GetType(), settings);
            ser.WriteObject(ms, obj);
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }
}
ThingName: thing_name1
Property1: 0
Property2: sure

ThingName: thing_name2
Property1: 34
Property2: absolutely

{"thing_name1":{"property1":0,"property2":"sure"},"thing_name2":{"property1":34,"property2":"absolutely"}}