Aynı property ismini bin kere yazmayı bırakın.
TabularJsonConverterFactory, POCO koleksiyonlarını her satırda aynı alan adlarını
tekrar tekrar yazan standart JSON yerine, tek bir header satırı ve altında
sade veri satırları olan tabular JSON formatına serialize / deserialize eden,
System.Text.Json üzerine kurulu hafif bir converter kütüphanesidir.
[
{ "Id": 1, "Name": "Ethem", "Age": 35 },
{ "Id": 2, "Name": "Ahmet", "Age": 28 },
{ "Id": 3, "Name": "Mehmet", "Age": 42 }
]
[ [ "Id", "Name", "Age" ], [ 1, "Ethem", 35 ], [ 2, "Ahmet", 28 ], [ 3, "Mehmet", 42 ] ]
Bu kütüphane ne işe yarar?
Aynı tipten çok sayıda kayıt taşıyan koleksiyonları JSON'a çevirirken, her kaydın kendi property isimlerini tekrar tekrar yazması israftır. TabularJsonConverterFactory bu tekrarı, isimleri bir kez tanımlayan bir header ve altındaki saf veri satırlarına ayırarak ortadan kaldırır — üstelik round-trip, yani hem serialize hem deserialize yönünde tam destekle.
Kütüphane; büyük koleksiyonlar, API response'ları, veri export/import işlemleri, log/event payload'ları, JSON tabanlı cache ve dosya tabanlı veri aktarımı gibi machine-to-machine senaryolarda değerlendirilmek üzere tasarlanmıştır. Bir sıkıştırma algoritması değildir; JSON'un yapısal tekrarını azaltan alternatif bir serialization formatıdır.
Neden tabular JSON?
1.000 kayıtlık bir koleksiyonda her satır aynı 4-5 property ismini yeniden yazar. Kayıt sayısı ve alan adı uzunluğu arttıkça bu tekrarın payload üzerindeki etkisi de büyür. Aşağıdaki canlı hesaplayıcı bunu somutlaştırıyor.
Hesaplama; musteri_id, musteri_adi, tutar, para_birimi, olusturma_tarihi
şeklinde 5 kolonluk örnek bir API kaydı üzerinden yaklaşık karakter sayımıyla yapılmıştır.
Gerçek kazanım, veri yapısına, alan adı uzunluğuna ve değerlerin boyutuna göre değişir —
kütüphane bir sıkıştırma garantisi vermez, gerçek sonuçlar veri setine göre ölçülmelidir.
İki farklı tabular temsil
İhtiyacınıza göre iki JSON şeklinden birini seçebilirsiniz.
[ [ "Id", "Name", "Age" ], [ 1, "Ethem", 35 ], [ 2, "Ahmet", 28 ], [ 3, "Mehmet", 42 ] ]
- En kısa JSON çıktısı, en az property-name tekrarı
- Tabular veri için doğal, CSV benzeri düşünce modeli
- Export senaryoları için uygun
{
"header": [ "Id", "Name", "Age" ],
"rows": [
[ 1, "Ethem", 35 ],
[ 2, "Ahmet", 28 ],
[ 3, "Mehmet", 42 ]
]
}
- Header ve data JSON içinde açıkça ayrılır, daha okunabilir
- API response'larında daha anlaşılır, debug sırasında daha rahat incelenir
- İleride metadata eklemeye daha uygun bir yapı
Kapsamlı, tek başına yeterli bir converter
Harici bir JSON framework'e ihtiyaç duymadan, mevcut System.Text.Json pipeline'ınıza doğrudan eklenir.
T[], List<T>, IEnumerable<T>, IReadOnlyList<T>, ICollection<T>, IList<T>.ref setter mekanizması.int?, DateTime? gibi tipleri güvenle işler.FormatterServices ile devam eder.Dört adımda entegrasyon
Converter'ı kaydedin, modelinizi tanımlayın, serialize/deserialize edin.
Converter'ı kaydedin
JsonConverterFactory olarak tasarlandığı için mevcut JsonSerializerOptions.Converters koleksiyonuna eklenir.
var options = new JsonSerializerOptions(); options.Converters.Add( new TabularJsonConverterFactory(TabularFormat.ArrayOfArrays));
Modelinizi tanımlayın
Public, okunabilir/yazılabilir property'ler otomatik olarak kolonlara dönüşür.
public sealed class Person { public int Id { get; set; } public string Name { get; set; } = string.Empty; public int Age { get; set; } }
Serialize edin
var people = new List<Person> { new() { Id = 1, Name = "Ethem", Age = 35 }, new() { Id = 2, Name = "Ahmet", Age = 28 } }; var json = JsonSerializer.Serialize(people, options); // [["Id","Name","Age"],[1,"Ethem",35],[2,"Ahmet",28]]
Deserialize edin
var people = JsonSerializer.Deserialize<List<Person>>(json, options); // people[0].Name == "Ethem"
JsonPropertyName ile
Mevcut [JsonPropertyName("customer_id")] attribute'ları header isimlerine yansır; hem JSON adı hem property adı eşleşme anahtarı olarak kullanılır.
Struct desteği
Value type'lar için ref tabanlı ayrı bir setter mekanizması kullanılır, böylece value semantics doğru şekilde korunur.
JSON validasyonu
Beklenmeyen bir kök yapı, eksik header/rows alanı ya da array olmayan bir satır geldiğinde standart JsonException fırlatılır.
Reflection bir kez, sonrası derlenmiş delegate
Her property erişiminde PropertyInfo.GetValue/SetValue çağırmak yerine,
metadata oluşturulurken expression tree'ler compile edilir ve tekrarlı erişimlerde
hazır delegate'ler kullanılır.
Metadata cache
Property metadata her işlemde yeniden üretilmez, tip başına statik generic alanlarda saklanır.
Header → index cache
Header isimlerinin property index'ine eşlenmesi önceden hazırlanır; her hücrede yeniden reflection araması yapılmaz.
Utf8JsonWriter
Serialization doğrudan Utf8JsonWriter üzerinden yapılır — System.Text.Json mimarisinin doğal genişleme noktası.
Standart JSON'a karşı
| Özellik | Standart Object JSON | TabularJsonConverterFactory |
|---|---|---|
| Property adı her satırda tekrar eder | Evet | Hayır |
| Header ayrı tutulabilir | Hayır | Evet |
| Kompakt representation | ◼︎ | ★★★★★ |
| İnsan tarafından okunabilirlik | ★★★ | ★★ |
| Tabular veri için uygunluk | ★★ | ★★★★★ |
| POCO round-trip | Evet | Evet |
| System.Text.Json uyumu | Evet | Evet |
ArrayOfArrays vs HeaderRows
| Özellik | ArrayOfArrays | HeaderRows |
|---|---|---|
| Kompaktlık | ★★★★★ | ★★★★ |
| Okunabilirlik | ★★★ | ★★★★★ |
| API response için uygunluk | ★★★★ | ★★★★★ |
| Debug kolaylığı | ★★★ | ★★★★★ |
| Metadata eklemeye uygunluk | ★★★ | ★★★★★ |
Doğru araç, doğru senaryo
Tabular JSON her durumda standart JSON'dan üstün değildir; asıl amacı standart JSON'un yerini almak değil, uygun senaryolarda alternatif sunmaktır.
✅ Uygun olduğu durumlar
- Çok sayıda aynı tipte kayıt taşıyan büyük koleksiyonlar
- Property isimlerinin sürekli tekrarını istemediğiniz API payload'ları
- SQL / DataTable benzeri tabular veriyi JSON olarak taşıma (database export)
- Aynı tipte çok sayıda kaydı tek payload'da taşıyan batch processing
- Tekrarlı JSON metadata'sını azaltmak istediğiniz cache senaryoları
- Producer/consumer aynı kolon şemasında anlaştığı data interchange
⚠️ Uygun olmadığı durumlar
- 3-5 kayıt gibi çok küçük koleksiyonlar — okunabilir standart JSON daha avantajlı
- JSON'un doğrudan insan tarafından okunması önemli olan public API'ler
- Self-describing (her satırın kendi alan adını taşıdığı) yapı beklenen entegrasyonlar
- Kesin bir sıkıştırma garantisi aranan senaryolar — bu bir sıkıştırma algoritması değildir