Dalam sistem saya saya sering beroperasi dengan kode bandara ( "YYZ"
, "LAX"
, "SFO"
, dll), mereka selalu dalam format yang sama persis (3 huruf, direpresentasikan sebagai huruf besar). Sistem ini biasanya menangani 25-50 kode (berbeda) ini per permintaan API, dengan lebih dari seribu total alokasi, mereka diedarkan melalui banyak lapisan aplikasi kita, dan cukup sering dibandingkan untuk kesetaraan.
Kami mulai dengan hanya memberikan string di sekitar, yang bekerja dengan baik untuk sedikit tetapi kami dengan cepat melihat banyak kesalahan pemrograman dengan mengirimkan kode yang salah di suatu tempat kode 3 digit diharapkan. Kami juga mengalami masalah di mana kami seharusnya melakukan perbandingan case-insensitive dan sebaliknya tidak, menghasilkan bug.
Dari sini, saya memutuskan untuk berhenti melewati string dan membuat Airport
kelas, yang memiliki konstruktor tunggal yang mengambil dan memvalidasi kode bandara.
public sealed class Airport
{
public Airport(string code)
{
if (code == null)
{
throw new ArgumentNullException(nameof(code));
}
if (code.Length != 3 || !char.IsLetter(code[0])
|| !char.IsLetter(code[1]) || !char.IsLetter(code[2]))
{
throw new ArgumentException(
"Must be a 3 letter airport code.",
nameof(code));
}
Code = code.ToUpperInvariant();
}
public string Code { get; }
public override string ToString()
{
return Code;
}
private bool Equals(Airport other)
{
return string.Equals(Code, other.Code);
}
public override bool Equals(object obj)
{
return obj is Airport airport && Equals(airport);
}
public override int GetHashCode()
{
return Code?.GetHashCode() ?? 0;
}
public static bool operator ==(Airport left, Airport right)
{
return Equals(left, right);
}
public static bool operator !=(Airport left, Airport right)
{
return !Equals(left, right);
}
}
Ini membuat kode kami jauh lebih mudah untuk dipahami dan kami menyederhanakan pemeriksaan kesetaraan, penggunaan kamus / set kami. Kita sekarang tahu bahwa jika metode kita menerima Airport
contoh bahwa ia akan berperilaku seperti yang kita harapkan, itu telah menyederhanakan pemeriksaan metode kita menjadi pemeriksaan referensi nol.
Namun yang saya perhatikan adalah pengumpulan sampah berjalan lebih sering, yang saya telusuri hingga banyak contoh Airport
pengumpulan.
Solusi saya untuk ini adalah untuk mengubah class
menjadi struct
. Sebagian besar itu hanya perubahan kata kunci, dengan pengecualian GetHashCode
dan ToString
:
public override string ToString()
{
return Code ?? string.Empty;
}
public override int GetHashCode()
{
return Code?.GetHashCode() ?? 0;
}
Untuk menangani kasing di mana default(Airport)
digunakan.
Pertanyaan saya:
Apakah membuat
Airport
kelas atau struct merupakan solusi yang baik secara umum, atau apakah saya memecahkan masalah yang salah / menyelesaikannya dengan cara yang salah dengan membuat tipe? Jika itu bukan solusi yang baik, apa solusi yang lebih baik?Bagaimana seharusnya aplikasi saya menangani instance tempat
default(Airport)
digunakan? Jenisdefault(Airport)
tidak masuk akal untuk aplikasi saya, jadi saya sudah melakukanif (airport == default(Airport) { throw ... }
di tempat-tempat di mana mendapatkan instanceAirport
(danCode
propertinya) sangat penting untuk operasi.
Catatan: Saya meninjau pertanyaan C # / VB struct - bagaimana cara menghindari case dengan nol nilai default, yang dianggap tidak valid untuk struktur yang diberikan? , dan Gunakan struct atau tidak sebelum mengajukan pertanyaan saya, namun saya pikir pertanyaan saya cukup berbeda untuk menjamin posnya sendiri.
default(Airport)
masalah adalah dengan tidak mengizinkan instance default. Anda dapat melakukannya dengan menulis konstruktor tanpa parameter dan melemparkan InvalidOperationException
atau NotImplementedException
di dalamnya.