I want to be able to convert a List<T>
into a specific JSON table-like format. In my case, the T
will always be a simple object (no nested properties). Here are two examples to illustrate what I want.
我希望能够将列表
Example #1: List<Person>
to JSON
示例#1:列表
// C# list of Persons
var list = new List<Person>() {
new Person() { First = "Jesse", Last = "Gavin", Twitter = "jessegavin" },
new Person() { First = "John", Last = "Sheehan", Twitter = "johnsheehan" }
};
// I want to transform the list above into a JSON object like so
{
columns : ["First", "Last", "Twitter"],
rows: [
["Jesse", "Gavin", "jessegavin"],
["John", "Sheehan", "johnsheehan"]
]
}
Example #2: List<Address>
to JSON
示例#2:列出 <地址> 到JSON
// C# list of Locations
var list = new List<Location>() {
new Location() { City = "Los Angeles", State = "CA", Zip = "90210" },
new Location() { City = "Saint Paul", State = "MN", Zip = "55101" },
};
// I want to transform the list above into a JSON object like so
{
columns : ["City", "State", "Zip"],
rows: [
["Los Angeles", "CA", "90210"],
["Saint Paul", "MN", "55101"]
]
}
Is there a way to tell JSON.net to serialize an object in this manner? If not, how could I accomplish this? Thanks.
有没有一种方法可以告诉JSON.net以这种方式序列化一个对象?如果没有,我怎么能做到呢?谢谢。
UPDATE:
Thanks to @Hightechrider's answer, I was able to write some code that solves the problem.
感谢@Hightechrider的回答,我能够编写一些代码来解决这个问题。
You can view a working example here https://gist.github.com/1153155
您可以在这里查看一个工作示例,https://gist.github.com/1153155。
3 个解决方案
#1
2
Using reflection you can get a list of properties for the type:
使用反射,您可以获得类型的属性列表:
var props = typeof(Person).GetProperties();
Given an instance of a Person
p you can get an enumeration of the property values thus:
给定一个人p的实例,您可以得到属性值的枚举,如下所示:
props.Select(prop => prop.GetValue(p, null))
Wrap those up in a generic method, add your favorite Json serialization and you have the format you want.
将它们打包到通用方法中,添加您最喜欢的Json序列化,您就得到了所需的格式。
#2
0
Assuming your using .Net 4 this should do everything you want. The class actually lets you convert to either XML or JSON. The Enum for CommunicationType is at the bottom. The serializer works best if the class your passing it has been decorated with DataContract & DataMember attributes. I've included a sample at the bottom. It will also take an anonymous type so long as it's all simple types.
假设你使用。net 4,这应该可以做你想做的一切。这个类实际上允许您转换成XML或JSON。通信类型的Enum位于底部。如果传递给它的类被修饰为DataContract和DataMember属性,则序列化器的工作效果最好。我在底部包括了一个样本。它还将采用匿名类型,只要它是所有简单类型。
Reflection would work as well but then you have to understand all the JSON nuances to output complex data types, etc. This used the built-in JSON serializer in .Net 4. One more note, because JSON does not define a date type .Net puts dates in a funky ASP.Net custom format. So long as your deserializing using the built-in deserializer it works just fine. I can dig up the documentation on that if you need.
反射也可以工作,但是您必须理解输出复杂数据类型的所有JSON细微差别,等等。还有一点要注意,因为JSON没有定义日期类型。net将日期放在时髦的ASP中。净自定义格式。只要您使用内置的反序列化器进行反序列化,它就可以正常工作。如果你需要的话,我可以找到相关文件。
using System;
using System.Xml.Serialization;
using System.Text;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Xml.Linq;
internal class Converter
{
public static string Convert<T>(T obj, CommunicationType format, bool indent = false, bool includetype = false)
{
if (format == CommunicationType.XML)
{
return ToXML<T>(obj, includetype, indent);
}
else if (format == CommunicationType.JSON)
{
return ToJSON<T>(obj);
}
else
{
return string.Empty;
}
}
private static string ToXML<T>(T obj, bool includetype, bool indent = false)
{
if (includetype)
{
XElement xml = XMLConverter.ToXml(obj, null, includetype);
if(indent) {
return xml.ToString();
}
else
{
return xml.ToString(SaveOptions.DisableFormatting);
}
}
else
{
System.Xml.Serialization.XmlSerializerNamespaces ns = new System.Xml.Serialization.XmlSerializerNamespaces();
XmlSerializer xs = new XmlSerializer(typeof(T));
StringBuilder sbuilder = new StringBuilder();
var xmlws = new System.Xml.XmlWriterSettings() { OmitXmlDeclaration = true, Indent = indent };
ns.Add(string.Empty, string.Empty);
using (var writer = System.Xml.XmlWriter.Create(sbuilder, xmlws))
{
xs.Serialize(writer, obj, ns);
}
string result = sbuilder.ToString();
ns = null;
xs = null;
sbuilder = null;
xmlws = null;
return result;
}
}
private static string ToJSON<T>(T obj)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
string result = string.Empty;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
ser.WriteObject(ms, obj);
result = encoding.GetString(ms.ToArray());
ms.Close();
encoding = null;
ser = null;
return result;
}
}
}
[DataContract()]
public enum CommunicationType : int
{
[XmlEnum("0"), EnumMember(Value = "0")]
XML = 0,
[XmlEnum("1"), EnumMember(Value = "1")]
JSON = 1
}
[DataContract(Namespace = "")]
public partial class AppData
{
[DataMember(Name = "ID")]
public string ID { get; set; }
[DataMember(Name = "Key")]
public string Key { get; set; }
[DataMember(Name = "Value")]
public string Value { get; set; }
[DataMember(Name = "ObjectType")]
public string ObjectType { get; set; }
}
#3
-1
Any specific reason why you don't need the standard format?
为什么不需要标准格式?
To actually answer the question:
来回答这个问题
Since this is something that is outside of JSON syntax I can't think of a way to implement this within the default framework.
由于这是JSON语法之外的东西,我想不出在默认框架内实现它的方法。
One solution would be to leverage attributes decorate the properties you want transported over the wired with a custom attribute and using Reflection cycle through the properties and output their property names as the column headers and then cycle throw the objects and write the values. Generic enough so it could be applied across other objects as well.
一种解决方案是利用属性装饰您希望通过有线传输的属性,使用自定义属性,并通过属性使用反射循环,并将属性名称作为列标题输出,然后循环抛出对象并写入值。足够通用,因此它也可以应用于其他对象。
public class Location
{
[JsonFooAttribute("City")]
public string city {get;set;}
[JsonFooAttribute("State")]
public string state {get;set;}
}
#1
2
Using reflection you can get a list of properties for the type:
使用反射,您可以获得类型的属性列表:
var props = typeof(Person).GetProperties();
Given an instance of a Person
p you can get an enumeration of the property values thus:
给定一个人p的实例,您可以得到属性值的枚举,如下所示:
props.Select(prop => prop.GetValue(p, null))
Wrap those up in a generic method, add your favorite Json serialization and you have the format you want.
将它们打包到通用方法中,添加您最喜欢的Json序列化,您就得到了所需的格式。
#2
0
Assuming your using .Net 4 this should do everything you want. The class actually lets you convert to either XML or JSON. The Enum for CommunicationType is at the bottom. The serializer works best if the class your passing it has been decorated with DataContract & DataMember attributes. I've included a sample at the bottom. It will also take an anonymous type so long as it's all simple types.
假设你使用。net 4,这应该可以做你想做的一切。这个类实际上允许您转换成XML或JSON。通信类型的Enum位于底部。如果传递给它的类被修饰为DataContract和DataMember属性,则序列化器的工作效果最好。我在底部包括了一个样本。它还将采用匿名类型,只要它是所有简单类型。
Reflection would work as well but then you have to understand all the JSON nuances to output complex data types, etc. This used the built-in JSON serializer in .Net 4. One more note, because JSON does not define a date type .Net puts dates in a funky ASP.Net custom format. So long as your deserializing using the built-in deserializer it works just fine. I can dig up the documentation on that if you need.
反射也可以工作,但是您必须理解输出复杂数据类型的所有JSON细微差别,等等。还有一点要注意,因为JSON没有定义日期类型。net将日期放在时髦的ASP中。净自定义格式。只要您使用内置的反序列化器进行反序列化,它就可以正常工作。如果你需要的话,我可以找到相关文件。
using System;
using System.Xml.Serialization;
using System.Text;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Xml.Linq;
internal class Converter
{
public static string Convert<T>(T obj, CommunicationType format, bool indent = false, bool includetype = false)
{
if (format == CommunicationType.XML)
{
return ToXML<T>(obj, includetype, indent);
}
else if (format == CommunicationType.JSON)
{
return ToJSON<T>(obj);
}
else
{
return string.Empty;
}
}
private static string ToXML<T>(T obj, bool includetype, bool indent = false)
{
if (includetype)
{
XElement xml = XMLConverter.ToXml(obj, null, includetype);
if(indent) {
return xml.ToString();
}
else
{
return xml.ToString(SaveOptions.DisableFormatting);
}
}
else
{
System.Xml.Serialization.XmlSerializerNamespaces ns = new System.Xml.Serialization.XmlSerializerNamespaces();
XmlSerializer xs = new XmlSerializer(typeof(T));
StringBuilder sbuilder = new StringBuilder();
var xmlws = new System.Xml.XmlWriterSettings() { OmitXmlDeclaration = true, Indent = indent };
ns.Add(string.Empty, string.Empty);
using (var writer = System.Xml.XmlWriter.Create(sbuilder, xmlws))
{
xs.Serialize(writer, obj, ns);
}
string result = sbuilder.ToString();
ns = null;
xs = null;
sbuilder = null;
xmlws = null;
return result;
}
}
private static string ToJSON<T>(T obj)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
string result = string.Empty;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
ser.WriteObject(ms, obj);
result = encoding.GetString(ms.ToArray());
ms.Close();
encoding = null;
ser = null;
return result;
}
}
}
[DataContract()]
public enum CommunicationType : int
{
[XmlEnum("0"), EnumMember(Value = "0")]
XML = 0,
[XmlEnum("1"), EnumMember(Value = "1")]
JSON = 1
}
[DataContract(Namespace = "")]
public partial class AppData
{
[DataMember(Name = "ID")]
public string ID { get; set; }
[DataMember(Name = "Key")]
public string Key { get; set; }
[DataMember(Name = "Value")]
public string Value { get; set; }
[DataMember(Name = "ObjectType")]
public string ObjectType { get; set; }
}
#3
-1
Any specific reason why you don't need the standard format?
为什么不需要标准格式?
To actually answer the question:
来回答这个问题
Since this is something that is outside of JSON syntax I can't think of a way to implement this within the default framework.
由于这是JSON语法之外的东西,我想不出在默认框架内实现它的方法。
One solution would be to leverage attributes decorate the properties you want transported over the wired with a custom attribute and using Reflection cycle through the properties and output their property names as the column headers and then cycle throw the objects and write the values. Generic enough so it could be applied across other objects as well.
一种解决方案是利用属性装饰您希望通过有线传输的属性,使用自定义属性,并通过属性使用反射循环,并将属性名称作为列标题输出,然后循环抛出对象并写入值。足够通用,因此它也可以应用于其他对象。
public class Location
{
[JsonFooAttribute("City")]
public string city {get;set;}
[JsonFooAttribute("State")]
public string state {get;set;}
}