У моїй системі я часто працюю з кодами аеропортів ( "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в ньому.