Soru Belirli bir tür serileştirirken ToString () yöntemini çağırmak için JSON.Net serializer nasıl oluşturulur?


C # sınıfları JSON dönüştürmek için Newtonsoft.Json serializer kullanıyorum. Bazı sınıflar için seri hale getiriciye tek tek özelliklere gereksinim duymuyorum, bunun yerine yalnızca nesne üzerinde ToString'i arayın;

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

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

ToString () yönteminin sonucu olarak serileştirilmiş Kişi nesnesini almak için ne yapmalıyım? Bunun gibi birçok dersim olabilir, bu yüzden Kişi sınıfı için özel bir seri hale getirici ile bitmek istemiyorum, herhangi bir gizem için geçerli olabileceğinden daha fazlasını istiyorum (tahmin ettiğim özellik).


20
2018-03-12 14:38


Menşei




Cevaplar:


Bunu bir özel ile kolayca yapabilirsiniz JsonConverter:

public class ToStringJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Dönüştürücüyü kullanmak için, dize olarak dizilenmesi gereken tüm sınıfları bir [JsonConverter] bu gibi özellik:

[JsonConverter(typeof(ToStringJsonConverter))]
public class Person
{
    ...
}

İşte dönüştürücüyü eylem halinde gösteren bir demo:

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); 
    }
}

Çıktı:

{
  "CompanyName": "Initrode",
  "Boss": "Head Honcho",
  "Employees": [
    "Joe Schmoe",
    "John Doe"
  ]
}

Ayrıca, dizeden bir nesneye dönüştürebilirsinizse, ReadJson dönüştürücü üzerinde bir yöntem gibi görünüyor public static Parse(string) yöntem ve onu çağırır. Not: dönüştürücüyü değiştirdiğinizden emin olun. CanRead dönüş yöntemi true (ya da sadece CanRead aksi takdirde) ReadJson asla çağrılmayacak.

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));
}

Tabii ki, yukarıdaki iş için, uygun bir şekilde uyguladığınızdan emin olmanız gerekir. Parse Eğer zaten mevcut değilse, dönüştürdüğünüz her bir sınıfın yöntemi. Bizim örneğimiz için Person Yukarıda gösterilen sınıf, bu yöntem şöyle görünebilir:

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;
}

Gidiş dönüş demo: https://dotnetfiddle.net/fd4EG4


35
2018-03-12 15:09



Çok teşekkürler. Tam olarak ihtiyacım olan şey. ÇALIŞIYOR bir cazibe gibi. - Vagif Abilov
Yardımcı olduğuma sevindim. - Brian Rogers
@BrianRogers Harika bir cevap için teşekkürler. ReadJson () 'ı dönüştürücünüze, bu dizgeyi ilgili iki özelliğe geri gönderecek şekilde nasıl uygulayacağınıza dair herhangi bir fikir verebilir misiniz diye merak ediyordum. - propagated
Bunun ilk başta benim için çalışmadığını fark ettim, ama ToString () yöntemimin 'geçersiz' yerine 'yeni' ile (neden olmasa da) süslenmiş olmasından kaynaklandı - bir kez iyi çalıştığını düzelttim. Paylaşım için teşekkürler. - Fijjit


Aşağıdaki örnekte, büyük ölçekte kullanılmak üzere tasarlanmamışsa, bunu yapmanın daha hızlı bir yolu vardır; Kayıt tipi özellik

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

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

1
2018-02-14 17:02





Newtonsoft'un JSON oluşturucu kitaplığını ve bu tür kodu kullanan Kişi tipindeki nesneyi Serilaize deneyebilirsiniz:

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
  });

0
2018-03-12 15:08



Teşekkürler. Brian'ın (özel dönüştürücü kullanarak) önerdiği bir yaklaşıma gittim. - Vagif Abilov


Çözümü test etmek için zamanım yok ama işe yaramalı. Kullandığınız tüm sınıfların kendinizin olduğunu varsayalım, neden bir ToString'in hepsini geçersiz kılmıyorsunuz ve Newtonsoft.Json serializer'ı kullanması gereken sınıflar sadece ToString yönteminde serileştirilebilir ve geri döndürülür. Bu şekilde, nesnenin serileştirilmiş dizesini almak istediğinizde ToString'i her zaman arayabilirsiniz.


-1
2018-03-12 14:42



İlk olarak, ToString ve Serialize'ı karıştırmak istemiyorum. Farklı amaçları var. İkincisi, karmaşık nesne grafiklerine sahip olabilirim, bu yüzden grafikleri hareket ettirmek ve serileştirme algoritmasını uygulamak için seri hale getiriciye güvenmeliyim. Senin appoach ile bu işe yaramaz. - Vagif Abilov