我希望有一个几乎与JSON相同的序列化格式,除了键值表示为<key>="<value>"
而不是"<key>":"<value>"
。
使用Newtonsoft,我制作了一个名为JsonConverter
的自定义TsonConverter
,效果相当不错,但它无法“看到”嵌入式字典。给出以下类型:
public class TraceyData
{
[Safe]
public string Application { get; set; }
[Safe]
public string SessionID { get; set; }
[Safe]
public string TraceID { get; set; }
[Safe]
public string Workflow { get; set; }
[Safe]
public Dictionary<string, string> Tags {get; set; }
[Safe]
public string[] Stuff {get; set;}
}
以下代码:
TsonConverter weird = new TsonConverter();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
settings.Converters.Add(weird);
var tracey = new TraceyData();
tracey.TraceID = Guid.NewGuid().ToString();
tracey.SessionID = "5";
tracey.Tags["Referrer"] = "http://www.sky.net/deals";
tracey.Stuff = new string[] { "Alpha", "Bravo", "Charlie" };
tracey.Application = "Responsive";
string stuff = JsonConvert.SerializeObject(tracey, settings);
我明白了:
[Application =“Responsive”SessionID =“5”TraceID =“082ef853-92f8-4ce8-9f32-8e4f792fb022”Tags = {“Referrer”:“http://www.sky.net/deals”} Stuff = [“Alpha”,“喝彩”, “查理”]]
显然我也覆盖了StartObject / EndObject表示法,用{]替换{}。否则结果不错。
但是,仍然存在内部字典的问题。为了
要转换字典以使用我的<key>="<value>"
格式,看起来我必须制作deep dictionary converter。
我想知道是否有更简单的方法来做到这一点。
也许Newtonsoft工具有一个“属性生成器”和“键值”生成器属性,我可以设置为全局处理这个属性吗?
有什么建议吗?
虽然我们在这里,但我想知道是否有一个我可以设置的StartObject / EndObject格式化程序属性覆盖,它将处理我上面显示的其他自定义。为这些简单的改动“跳过”制作JsonConverter工具会很好。
顺便提及:
[Safe]
属性选择要序列化的属性。这是另一个不错的选择。如果JSon设置可以公开一个“属性处理程序”属性,让我可以覆盖我自己的常用JSon属性,这将是非常好的。下面是我制作的TraceConverter。它引用了一个只包含属性信息的FieldMetaData
类。
public class TsonConverter : JsonConverter
{
public override bool CanRead
{
get
{
return false;
}
}
public override bool CanConvert(Type ObjectType)
{
return DataClassifier.TestForUserType(ObjectType);
}
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
Type objType = value.GetType();
var props = objType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var propMap = from p in props
from a in p.GetCustomAttributes(typeof(ProfileAttribute), false)
select new FieldMetaData(p, (ProfileAttribute)a);
//writer.WriteStartObject();
writer.WriteStartArray();
bool loopStarted = true;
foreach(var prop in propMap){
object rawValue = prop.GetValue(value);
if (rawValue != null || serializer.NullValueHandling == NullValueHandling.Include)
{
string jsonValue = JsonConvert.SerializeObject(prop.GetValue(value), this);
if (loopStarted)
{
loopStarted = false;
writer.WriteRaw(String.Format("{0}={1}", prop.Name, jsonValue));
}
else
{
writer.WriteRaw(String.Format(" {0}={1}", prop.Name, jsonValue));
}
}
//writer.WriteRaw(String.Format("{0}={1}", prop.Name, prop.GetValue(value)));
//writer.WritePropertyName(prop.Name, false);
//writer.WriteValue(prop.GetValue(value));
}
writer.WriteEndArray();
}
public override object ReadJson(
JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
答案 0 :(得分:1)
您不需要创建自己的转换器,而是需要创建自己的JsonWriter
子类来写入自定义文件格式。 (这就是Json.NET实现其BsonWriter
的方式。)在您的情况下,您的文件格式足够接近JSON,您可以从JsonTextWriter
继承:
public class TsonTextWriter : JsonTextWriter
{
TextWriter _writer;
public TsonTextWriter(TextWriter textWriter)
: base(textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
QuoteName = false;
_writer = textWriter;
}
public override void WriteStartObject()
{
SetWriteState(JsonToken.StartObject, null);
_writer.Write('[');
}
protected override void WriteEnd(JsonToken token)
{
switch (token)
{
case JsonToken.EndObject:
_writer.Write(']');
break;
default:
base.WriteEnd(token);
break;
}
}
public override void WritePropertyName(string name)
{
WritePropertyName(name, true);
}
public override void WritePropertyName(string name, bool escape)
{
SetWriteState(JsonToken.PropertyName, name);
var escaped = name;
if (escape)
{
escaped = JsonConvert.ToString(name, '"', StringEscapeHandling);
escaped = escaped.Substring(1, escaped.Length - 2);
}
// Maybe also escape the space character if it appears in a name?
_writer.Write(escaped.Replace("=", @"\u003d"));// Replace "=" with unicode escape sequence.
_writer.Write('=');
}
/// <summary>
/// Writes the JSON value delimiter. (Remove this override if you want to retain the comma separator.)
/// </summary>
protected override void WriteValueDelimiter()
{
_writer.Write(' ');
}
/// <summary>
/// Writes an indent space.
/// </summary>
protected override void WriteIndentSpace()
{
// Do nothing.
}
}
完成此操作后,现在所有类将在您使用此编写器时序列化为您的自定义格式,例如:
var tracey = new TraceyData();
tracey.TraceID = Guid.NewGuid().ToString();
tracey.SessionID = "5";
tracey.Tags["Referrer"] = "http://www.sky.net/deals";
tracey.Stuff = new string[] { "Alpha", "Bravo", "Charlie" };
tracey.Application = "Responsive";
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
using (var sw = new StringWriter())
{
using (var jsonWriter = new TsonTextWriter(sw))
{
JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, tracey);
}
Debug.WriteLine(sw.ToString());
}
生成输出
[Application="Responsive" SessionID="5" TraceID="2437fe67-9788-47ba-91ce-2e5b670c2a34" Tags=[Referrer="http://www.sky.net/deals"] Stuff=["Alpha" "Bravo" "Charlie"]]
至于根据是否存在[Safe]
属性来决定是否序列化属性,这是第二个问题。您需要创建自己的ContractResolver
并覆盖CreateProperty
,例如:Using JSON.net, how do I prevent serializing properties of a derived class, when used in a base class context?
<强>更新强>
如果要保留数组的逗号分隔符而不保留对象,请按如下所示修改WriteValueDelimiter
:
/// <summary>
/// Writes the JSON value delimiter. (Remove this override if you want to retain the comma separator.)
/// </summary>
protected override void WriteValueDelimiter()
{
if (WriteState == WriteState.Array)
_writer.Write(',');
else
_writer.Write(' ');
}