C# 如何使JSON.Net序列化程序在序列化特定类型时调用ToString()?

C# 如何使JSON.Net序列化程序在序列化特定类型时调用ToString()?,c#,json,serialization,json.net,tostring,C#,Json,Serialization,Json.net,Tostring,我正在使用Newtonsoft.Json序列化程序将C#类转换为Json。对于某些类,我不需要序列化程序来创建单个属性的实例,而只需要调用对象上的ToString,即 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public override string ToString() { return string.Format("{

我正在使用Newtonsoft.Json序列化程序将C#类转换为Json。对于某些类,我不需要序列化程序来创建单个属性的实例,而只需要调用对象上的ToString,即

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }

   public override string ToString() { return string.Format("{0} {1}", FirstName, LastName ); }
}

我应该怎么做才能将Person对象序列化为其ToString()方法的结果?我可能有很多这样的类,所以我不想最终得到一个特定于Person类的序列化程序,我希望有一个可以应用于任何类的序列化程序(我猜是通过属性)。

我没有时间测试我的解决方案,但它应该可以工作。假设您正在使用的所有类都是您自己的,为什么不对所有这些类执行ToString重写,并且需要使用Newtonsoft.Json序列化程序的类可以在ToString方法中序列化并返回。这样,当您想要获取对象的序列化字符串时,您总是可以调用ToString。

您只需尝试Newtonsoft的JSON builder库,并使用以下代码序列化Person类型的对象:

Dictionary<string, object> collection = new Dictionary<string, object>()
    {
      {"First", new Person(<add FirstName as constructor>)},
      {"Second", new Person(<add LastName as constructor>)},

    };
string json = JsonConvert.SerializeObject(collection, Formatting.Indented, new JsonSerializerSettings
  {
    TypeNameHandling = TypeNameHandling.All,
    TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
  });
Dictionary collection=newdictionary()
{
{“第一”,新人(),
{“第二”,新人(),
};
string json=JsonConvert.SerializeObject(集合、格式、缩进、新JsonSerializerSettings
{
TypeNameHandling=TypeNameHandling.All,
TypeNameAssemblyFormat=FormatterAssemblyStyle.Simple
});

您可以通过自定义:

要使用转换器,请使用
[JsonConverter]
属性将任何需要序列化为字符串的类修饰为如下:

[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    ...
}
public static Person Parse(string s)
{
    if (string.IsNullOrWhiteSpace(s))
        throw new ArgumentException("s cannot be null or empty", "s");

    string[] parts = s.Split(new char[] { ' ' }, 2);
    Person p = new Person { FirstName = parts[0] };
    if (parts.Length > 1)
        p.LastName = parts[1];

    return p;
}
下面是一个演示,演示了转换器的工作情况:

class Program
{
    static void Main(string[] args)
    {
        Company company = new Company
        {
            CompanyName = "Initrode",
            Boss = new Person { FirstName = "Head", LastName = "Honcho" },
            Employees = new List<Person>
            {
                new Person { FirstName = "Joe", LastName = "Schmoe" },
                new Person { FirstName = "John", LastName = "Doe" }
            }
        };

        string json = JsonConvert.SerializeObject(company, Formatting.Indented);
        Console.WriteLine(json);
    }
}

public class Company
{
    public string CompanyName { get; set; }
    public Person Boss { get; set; }
    public List<Person> Employees { get; set; }
}

[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public override string ToString() 
    { 
        return string.Format("{0} {1}", FirstName, LastName); 
    }
}

如果您还需要能够从字符串转换回对象,那么可以在转换器上实现
ReadJson
方法,以便它查找
公共静态解析(字符串)
方法并调用它。注意:确保将转换器的
CanRead
方法更改为返回
true
(或者干脆删除
CanRead
重载),否则将永远不会调用
ReadJson

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    MethodInfo parse = objectType.GetMethod("Parse", new Type[] { typeof(string) });
    if (parse != null && parse.IsStatic && parse.ReturnType == objectType)
    {
        return parse.Invoke(null, new object[] { (string)reader.Value });
    }

    throw new JsonException(string.Format(
        "The {0} type does not have a public static Parse(string) method that returns a {0}.", 
        objectType.Name));
}
当然,要使上述方法起作用,您还需要确保在您转换的每个类上实现一个合适的
Parse
方法(如果它还不存在的话)。对于上面显示的示例
Person
类,该方法可能如下所示:

[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    ...
}
public static Person Parse(string s)
{
    if (string.IsNullOrWhiteSpace(s))
        throw new ArgumentException("s cannot be null or empty", "s");

    string[] parts = s.Split(new char[] { ' ' }, 2);
    Person p = new Person { FirstName = parts[0] };
    if (parts.Length > 1)
        p.LastName = parts[1];

    return p;
}

往返演示:

如果不打算大规模使用,有一种更快的方法,在下面的示例中,它是针对RecordType属性完成的

[JsonIgnore]
public RecordType RecType { get; set; }

[JsonProperty(PropertyName = "RecordType")]
private string RecordTypeString => RecType.ToString();

首先,我不想混合使用ToString和序列化。它们有不同的目的。第二,我可以有复杂的对象图,所以我应该依赖序列化程序来遍历图并应用序列化算法。如果你同意,这是行不通的。非常感谢。正是我需要的。工作起来很有魅力。@BrianRogers谢谢你的精彩回答。我想知道您是否可以提供一些关于如何在转换器中实现ReadJson()的见解,以便它将该字符串反序列化回其各自的两个属性?我发现这在一开始对我不起作用,但这是因为我的ToString()方法用“new”而不是“override”修饰(不知道为什么)-有一次我纠正了,它工作得很好。谢谢分享,谢谢。我选择了Brian建议的方法(使用自定义转换器)。