CLR tipi aynı olmak zorunda değil.
Sadece şema uyumlu olsun.
SchemaBinarySerializer, "aynı tip serialize edilir, aynı tip deserialize edilir" varsayımını terk eder.
Bunun yerine verinin mantıksal şemasını esas alır — böylece CustomerV1 ile yazılan binary veri,
yapısal olarak uyumlu CustomerV2 ile okunabilir. Field sırası, class adı, hatta struct/class farkı önemli değildir.
BinaryFormatter kaldırıldı. Boşluk kaldı.
Microsoft, güvenlik açıkları nedeniyle .NET'in kendi BinaryFormatter'ını
kademeli olarak devre dışı bıraktı ve .NET 9 ile kaldırdı. Binary serialization'a ihtiyaç duyan
pek çok sistem (cache, IPC, dosya formatları, eski protokoller) için resmi bir alternatif bırakılmadı.
Geleneksel yaklaşımın kırıldığı yer
Klasik binary serializer'lar CLR tipini merkeze koyar: aynı tip yazılır, aynı tip okunur. Model bir gün değişirse (alan eklenir, sıra değişir, tip taşınır) stream okunamaz hâle gelir.
// Serialize CustomerV1 ↓ binary ↓ // Deserialize — aynı tip zorunlu CustomerV1
// Serialize CustomerV1 ↓ logical schema ↓ binary ↓ // Deserialize — schema uyumlu her tip schema matching ↓ CustomerV2
Aynı CLR tipi gerekmez, sadece aynı şema
Varsayılan eşleştirme modeli ObjectTypeMatching.Structural'dır. İki farklı CLR tipi,
aynı isimde ve aynı tipte member'lara sahipse — sıraları farklı olsa bile — aynı mantıksal şemayı paylaşır.
public sealed class AddressV1 { public string City { get; set; } public int ZipCode { get; set; } }
public sealed class AddressV2 { public int ZipCode { get; set; } public string City { get; set; } } // AddressV1 ≠ AddressV2 (CLR tipi olarak) // fakat şema olarak ikisi de aynı: // Address { City: String, ZipCode: Int32 } // → AddressV1 serialize edilir, AddressV2 deserialize edilebilir ✅
Öne çıkan özellikler
Tek bir .csproj, harici bağımlılık yok. İşaretli her madde şu anki sürümde aktif.
Deterministic, platformdan bağımsız Member ID
Her member için sabit bir kimlik üretilir. Bu kimliğe yalnızca member adı girer — namespace, assembly, CLR tip adı ya da işletim sistemi bilgisi karışmaz.
Sonuç: aynı member adı, her platformda aynı ID'ye karşılık gelir.
Metadata oluşturulurken hash çakışmaları da ayrıca tespit edilir; sessizce yanlış member'a bağlanmaz.
Schema Evolution: eski veri yeni modelle, yeni veri eski modelle
Field ekleme, field kaldırma ve sıra değişikliği stream'i bozmaz. Bilinmeyen member'lar okunmadan atlanır
(SkipValue()), eksik member'lar için ise varsayılan değer kullanılır.
V1 BINARY → Id, Name
CustomerV2 bekliyor → Id, Name, Email
V2 BINARY → Id, Name, Email
CustomerV1 bekliyor → Id, Name
byte[] data = SchemaBinarySerializer.Serialize(customerV1); CustomerV2 customerV2 = SchemaBinarySerializer.Deserialize<CustomerV2>(data); // Id, Name, Address eşleşir → değer korunur // Email, CreatedAt (V1'de yok) → default değer
Üç eşleştirme modu
İhtiyaca göre esnek şema eşleştirmesi ile katı tip kontrolü arasında seçim yapılabilir.
En esnek model. CLR tipi aynı olmasa da şema uyumluysa deserialize başarılı olur.
var options = new SchemaBinarySerializerOptions { ObjectTypeMatching = ObjectTypeMatching.Structural }; // AddressV1 → schema matching → AddressV2 (CLR tipi önemsiz)
Daha katı bir sözleşme isteyen uygulamalar için. CLR tip kimliği de eşleşme kararına dahil olur.
var options = new SchemaBinarySerializerOptions { ObjectTypeMatching = ObjectTypeMatching.ExactType }; // Address → Address : uyumlu // Address → MyAddress : uyumsuz (reddedilir)
API seviyesinde yer ayrılmış bir extension point. İleride Animal → Dog gibi kalıtım
tabanlı eşleştirme senaryoları için kullanılabilecek; wire format'ın uzun vadeli stabilitesini bozmamak adına
ilk sürümde bilinçli olarak devre dışı bırakıldı.
Primitive'den collection'a, nested object'e kadar
Class, struct, nested object, koleksiyonlar ve tüm temel .NET primitive tipleri kendi deterministic wire encoding'leriyle desteklenir.
Primitive eşleşmesinde yalnızca member adı yeterli değildir — int Value ile
string Value aynı ada sahip olsa da farklı şema olarak değerlendirilir; her primitive
kendi deterministic tip koduyla taşınır.
Performans odaklı, düşük allocation
Reflection yalnızca ilk metadata keşfinde kullanılır; sonrasında her şey cache'lenmiş ve compile edilmiştir.
ConcurrentDictionary<Type, MemberMetadataCollection> ile her tip için tek seferlik reflection keşfi.RuntimeHelpers.GetUninitializedObject.var buffer = new ArrayBufferWriter<byte>(); SchemaBinarySerializer.Serialize(buffer, customer);
Dış kaynaklı binary veri kontrolsüz işlenmez
Deserialize sırasında ağdan veya harici depolamadan gelen veri, açık limitlerle sınırlandırılır.
Beklenmeyen bir değer (örn. milyarlarca eleman içeren bir koleksiyon iddiası) doğrudan devasa
allocation'a yol açmaz — InvalidDataException ile reddedilir.
Geçersiz wire type, geçersiz schema ID veya geçersiz descriptor — hepsi sessizce yoksayılmak yerine
InvalidDataException fırlatır.
Geleneksel yaklaşıma karşı
| Özellik | CLR merkezli geleneksel yaklaşım | SchemaBinarySerializer |
|---|---|---|
| Aynı CLR type gerekli mi | Genellikle evet | Structural modda hayır |
| Member sırası önemli mi | Sıklıkla önemli | Önemli değil |
| Schema evolution | Kütüphaneye bağlı | Temel özellik |
| Unknown field skip | Değişken | Destekleniyor |
| Stable member ID | Değişken | FNV-1a 64-bit |
| Class → farklı class | Genellikle sınırlı | Destekleniyor |
| Collection modeli | CLR type merkezli olabilir | Logical category |
| Harici serializer bağımlılığı | Sıklıkla var | Yok |
| Metadata / compiled accessor cache | Değişken | Var |
| IBufferWriter desteği | Değişken | Var |
Ne zaman tercih edilmeli
Binary storage
Veritabanında binary column / blob olarak saklanan, zamanla model değişebilecek veriler.
Network protokolü
Sunucu V1 ile client V2'nin aynı anda farklı model sürümleriyle konuşabildiği senaryolar.
Cache
Uygulama yeniden başlatıldığında ya da model sürümü değiştiğinde bile okunabilir binary cache.
Microservice / dağıtık sistemler
Servisler arası binary mesajlaşmada bağımsız sürümlenen modeller.
Büyük binary payload
Görsel, video, dosya, sıkıştırılmış veya şifrelenmiş veri — byte[] doğrudan binary olarak işlenir.
IPC / internal protokol
Harici bağımlılık istemeyen server, Windows Service veya Linux service içi haberleşme.
Tasarım prensipleri
API yüzeyi küçük tutulur
En basit kullanımdan özelleştirilmiş options ve buffer writer'a kadar tek bir statik API.
byte[] data = SchemaBinarySerializer.Serialize(value);
T result = SchemaBinarySerializer.Deserialize<T>(data);
var options = new SchemaBinarySerializerOptions { ObjectTypeMatching = ObjectTypeMatching.Structural, MaxDepth = 256 }; byte[] data = SchemaBinarySerializer.Serialize(value, options); T result = SchemaBinarySerializer.Deserialize<T>(data, options);
Aynı CLR tipini korumak zorunda kalmadan, binary veriyle üretime çıkın.
.NET 6.0 · MIT lisansı · tek proje, sıfır harici bağımlılık.
DSO.Core.SchemaBinarySerializer.csproj