.NET 6.0 · MIT Lisanslı · 3. parti bağımlılık yok

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.

CustomerV1 Id : Int32 Name : String Address: Addr logical schema MemberId (FNV-1a) MemberName TypeDescriptor binary wire format 01 4B F2 9A 00 1D 88 CustomerV2 Name : String Id : Int32 Address: Addr Email : default
serialize → schema graph → binary → schema matching → deserialize farklı CLR tipi · farklı field sırası · sorun değil
01 — Neden bu kütüphane var

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ı.

BinaryFormatter.Serialize / Deserialize artık desteklenmiyor. Ekiplerin önünde iki seçenek kaldı: metin tabanlı formatlara (JSON, vs.) geçip performans ve boyut kaybetmek, ya da 3. parti bir binary serializer'a (MessagePack, protobuf-net, MemoryPack) bağımlı olup şema/versiyon yönetimini onların kurallarına göre yeniden kurmak. SchemaBinarySerializer üçüncü bir yol sunar: .NET 6 BCL üzerine kurulu, bağımlılıksız, kendi şema modeline sahip bir binary serializer.

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.

Geleneksel model
serialize → deserialize
// Serialize
CustomerV1
    ↓
binary
    ↓
// Deserialize — aynı tip zorunlu
CustomerV1
SchemaBinarySerializer
serialize → schema → deserialize
// Serialize
CustomerV1
    ↓
logical schema
    ↓
binary
    ↓
// Deserialize — schema uyumlu her tip
schema matching
    ↓
CustomerV2
02 — Temel fark

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.

AddressV1.cs
public sealed class AddressV1
{
    public string City { get; set; }
    public int ZipCode { get; set; }
}
AddressV2.cs — farklı sıra, farklı CLR tipi
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 ✅
03 — Kapsam

Öne çıkan özellikler

Tek bir .csproj, harici bağımlılık yok. İşaretli her madde şu anki sürümde aktif.

04 — Wire format'ın temeli

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.

MemberName
UTF-8 bytes
FNV-1a 64-bit
ulong Member ID

Sonuç: aynı member adı, her platformda aynı ID'ye karşılık gelir.

Windows x64
Linux x64
Linux ARM64
macOS ARM64
— hepsinde aynı stable ID —

Metadata oluşturulurken hash çakışmaları da ayrıca tespit edilir; sessizce yanlış member'a bağlanmaz.

05 — Sürüm toleransı

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

Id okunur
Name okunur

CustomerV2 bekliyor → Id, Name, Email

Id okunur
Name okunur
Email default

V2 BINARY → Id, Name, Email

Id okunur
Name okunur
Email skip

CustomerV1 bekliyor → Id, Name

Id okunur
Name okunur
örnek — farklı iki tip arasında
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
06 — Esneklik / katılık dengesi

Üç eşleştirme modu

İhtiyaca göre esnek şema eşleştirmesi ile katı tip kontrolü arasında seçim yapılabilir.

● aktif · varsayılan

En esnek model. CLR tipi aynı olmasa da şema uyumluysa deserialize başarılı olur.

options
var options = new SchemaBinarySerializerOptions
{
    ObjectTypeMatching = ObjectTypeMatching.Structural
};

// AddressV1 → schema matching → AddressV2 (CLR tipi önemsiz)
● aktif

Daha katı bir sözleşme isteyen uygulamalar için. CLR tip kimliği de eşleşme kararına dahil olur.

options
var options = new SchemaBinarySerializerOptions
{
    ObjectTypeMatching = ObjectTypeMatching.ExactType
};

// Address → Address    : uyumlu
// Address → MyAddress  : uyumsuz (reddedilir)
◐ hazır, henüz aktif değil

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ı.

07 — Tip desteği

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.

Boolean
Byte / SByte
Int16 / UInt16
Int32 / UInt32
Int64 / UInt64
Single / Double
Decimal
Char
String
Guid
DateTime
DateTimeOffset
TimeSpan
byte[] / Binary
Enum (underlying type ile)
Nullable<T>
Array
List<T> / ICollection
Dictionary<K,V>
HashSet<T> / ISet<T>
Nested class / struct
Runtime polymorphism

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.

08 — Mimari

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.

Metadata cache
ConcurrentDictionary<Type, MemberMetadataCollection> ile her tip için tek seferlik reflection keşfi.
Compiled getter/setter
Her member için expression tree üzerinden derlenmiş delegate; runtime'da reflection çağrısı yok.
Compiled object factory
Deserialize sırasında nesne oluşturma da cache'lenir: value type → parametresiz constructor → RuntimeHelpers.GetUninitializedObject.
Collection accessor cache
Collection ve dictionary erişimleri için derlenmiş Add/Setter delegate'leri.
IBufferWriter<byte>
Doğrudan mevcut buffer altyapısına yazabilir — network pipeline, memory pool, custom buffer senaryoları için.
IBufferWriter kullanımı
var buffer = new ArrayBufferWriter<byte>();

SchemaBinarySerializer.Serialize(buffer, customer);
09 — Kontrolsüz veri güvenliği

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.

MaxSchemaCount
100.000 (varsayılan)
MaxSchemaMembers
100.000 (varsayılan)
MaxCollectionCount
10.000.000 (varsayılan)
MaxBinaryLength
256 MB (varsayılan)
MaxStringByteLength
64 MB (varsayılan)
MaxDepth
256 (varsayılan)

Geçersiz wire type, geçersiz schema ID veya geçersiz descriptor — hepsi sessizce yoksayılmak yerine InvalidDataException fırlatır.

10 — Kıyaslama

Geleneksel yaklaşıma karşı

ÖzellikCLR merkezli geleneksel yaklaşımSchemaBinarySerializer
Aynı CLR type gerekli miGenellikle evetStructural modda hayır
Member sırası önemli miSıklıkla önemliÖnemli değil
Schema evolutionKütüphaneye bağlıTemel özellik
Unknown field skipDeğişkenDestekleniyor
Stable member IDDeğişkenFNV-1a 64-bit
Class → farklı classGenellikle sınırlıDestekleniyor
Collection modeliCLR type merkezli olabilirLogical category
Harici serializer bağımlılığıSıklıkla varYok
Metadata / compiled accessor cacheDeğişkenVar
IBufferWriter desteğiDeğişkenVar
11 — Kullanım alanları

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.

12 — Felsefe

Tasarım prensipleri

01
Schema>CLR Type Identity
02
Member ID>Member Order
03
Structural Compatibility>Same CLR Type
04
Primitive Type Code>CLR Type Name
05
Logical Collection Descriptor>Concrete Collection Type
06
Deterministic Hash>Runtime HashCode
07
Cached Metadata>Repeated Reflection
08
Buffer Writer>Gereksiz ara buffer
09
Explicit Limits>Kontrolsüz Allocation
10
Versioned Wire Format>Implicit Format Changes
13 — Kullanım

API yüzeyi küçük tutulur

En basit kullanımdan özelleştirilmiş options ve buffer writer'a kadar tek bir statik API.

en basit kullanım
byte[] data = SchemaBinarySerializer.Serialize(value);

T result = SchemaBinarySerializer.Deserialize<T>(data);
özel options ile
var options = new SchemaBinarySerializerOptions
{
    ObjectTypeMatching = ObjectTypeMatching.Structural,
    MaxDepth = 256
};

byte[] data = SchemaBinarySerializer.Serialize(value, options);
T result = SchemaBinarySerializer.Deserialize<T>(data, options);
DSO.Core.SchemaBinarySerializer

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.

dotnet add reference DSO.Core.SchemaBinarySerializer.csproj