У моїй системі я часто працюю з кодами аеропортів ( "YYZ"
, "LAX"
, "SFO"
і т.д.), вони завжди знаходяться в тому ж форматі (3 листи, представлений в верхньому регістрі). Зазвичай система займається 25-50 цими (різними) кодами на запит API, загалом - понад тисяча виділень, вони передаються через багато шарів нашої програми, і їх порівнюють за рівність досить часто.
Ми почали з просто проходження рядків навколо, що трохи спрацювало, але ми швидко помітили багато помилок програмування, передавши неправильний код десь тризначний код. Ми також стикалися з проблемами, в яких ми повинні проводити порівняльне врахування випадків, а замість цього - не, внаслідок чого виникають помилки.
З цього я вирішив зупинити проходження рядків навколо та створити Airport
клас, який має єдиний конструктор, який приймає та підтверджує код аеропорту.
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);
}
}
Це значно спростило наш код і ми спростили наші перевірки рівності, словник / встановлені звичаї. Тепер ми знаємо, що якщо наші методи приймають Airport
екземпляр, що він буде вести себе так, як ми очікуємо, він спростив нашу перевірку методів до нульової контрольної перевірки.
Однак я помітив, що збирання сміття працює набагато частіше, що я відслідковував до багатьох випадків Airport
збирання.
Моє рішення для цього полягало в перетворенні class
в struct
. Переважно це була лише зміна ключового слова, за винятком GetHashCode
та ToString
:
public override string ToString()
{
return Code ?? string.Empty;
}
public override int GetHashCode()
{
return Code?.GetHashCode() ?? 0;
}
Для обробки справи, де default(Airport)
використовується.
Мої запитання:
Чи було створення
Airport
класу чи структури хорошим рішенням взагалі, чи я вирішую неправильну задачу / вирішую її неправильним шляхом, створюючи тип? Якщо це не гарне рішення, яке краще рішення?Як моя програма повинна обробляти випадки, коли
default(Airport)
використовується? Типdefault(Airport)
мого додатку не є чутливим, тому я робивif (airport == default(Airport) { throw ... }
місця, де отримання екземпляраAirport
(та йогоCode
властивості) є критично важливим для операції.
Примітки. Я переглянув питання C # / VB structure - як уникнути випадку з нульовими значеннями за замовчуванням, що вважається недійсним для даної структури? , і використовуйте структуру чи ні перед тим, як ставити запитання, проте я думаю, що мої запитання є досить різними, щоб гарантувати власну посаду.
default(Airport)
проблему - просто заборонити екземпляри за замовчуванням. Ви можете зробити це, написавши конструктор без параметрів і метання InvalidOperationException
або NotImplementedException
в ньому.