хочется создать новый тип на основе строки, чтобы были запрещены операции сравнения, присваивания к строке.
Есть какое-то общепринятое решение? Типа best practice.
У меня что-то много boilerplate кода получается
public struct LanguageCode
{
public LanguageCode(string v)
{
value = v;
}
private readonly string value;
public override bool Equals(object obj)
=> obj is LanguageCode lc
? lc.value.Equals(value, System.StringComparison.CurrentCultureIgnoreCase)
: false;
public static bool operator ==(LanguageCode fst, LanguageCode snd)
=> fst.value.Equals(snd.value, System.StringComparison.CurrentCultureIgnoreCase);
public static bool operator !=(LanguageCode fst, LanguageCode snd)
=> !fst.value.Equals(snd.value, System.StringComparison.CurrentCultureIgnoreCase);
public override int GetHashCode()
=> value.ToLower().GetHashCode();
public static LanguageCode Default
=> new LanguageCode("en");
public override string ToString()
=> value.ToLower();
}
Для одиночного такого типа нормально. Но если хочу завести таких ещё парочку? Copy-Paste?
Здравствуйте, sergii.p, Вы писали:
SP>хочется создать новый тип на основе строки, чтобы были запрещены операции сравнения, присваивания к строке. SP>Для одиночного такого типа нормально. Но если хочу завести таких ещё парочку? Copy-Paste?
Здравствуйте, sergii.p, Вы писали: SP>хочется создать новый тип на основе строки,
OK SP>чтобы были запрещены операции сравнения, присваивания к строке.
Это как? Можно увидеть пример того, что "разрешено", но нужно запретить? SP>Есть какое-то общепринятое решение? Типа best practice. SP>У меня что-то много boilerplate кода получается… SP>Для одиночного такого типа нормально. Но если хочу завести таких ещё парочку? Copy-Paste?
По идее, если я правильно понял,задачу, код выше можно переписать так вот:
public readonly struct LanguageCode : IEquatable<LanguageCode>
{
private readonly string value;
public LanguageCode(string value) => this.value = value;
public static LanguageCode Default { get; } = new LanguageCode("en");
public bool Equals(LanguageCode other) => String.Equals(value, other.value, StringComparison.CurrentCultureIgnoreCase);
public override bool Equals(object? obj) => obj is LanguageCode other && Equals(other);
public override int GetHashCode() => value?.GetHashCode(StringComparison.CurrentCultureIgnoreCase) ?? 0;
public override string ToString() => value?.ToLower() ?? String.Empty;
public static bool operator ==(LanguageCode left, LanguageCode right) => left.Equals(right);
public static bool operator !=(LanguageCode left, LanguageCode right) => !(left == right);
}
и сделать, например, source generator который будет дописывать за вас boilerplate. Лично для меня, тут проще вручную обойтись, выглядит не слишком плохо.
Можно пойти дальше и использовать record:
public readonly record struct LanguageCode
{
public LanguageCode(string value) => Value = value?.ToLower() ?? String.Empty;
public static LanguageCode Default { get; } = new LanguageCode("en");
private string Value { get; }
public override string ToString() => Value;
}
Тут компилятор вам сам нагенерит тот же код, который я привёл выше.
Я бы постарался бы сделать так, если я правильно понял Default, чтобы в подобной структурке, будь она мне нужна, выполнялось бы следующее равенство:
default(LanguageCode) == LanguageCode.Default;
Через record этого пока не добиться, остаётся "ручная" реализация сравнения.
Например, так можно
public readonly struct LanguageCode : IEquatable<LanguageCode>
{
public const string DefaultLanguageCode = "en";
private readonly string? value;
public LanguageCode(string value) => this.value = value;
public static LanguageCode Default { get; } = default;
private string Value => value ?? DefaultLanguageCode;
public bool Equals(LanguageCode other) => String.Equals(Value, other.Value, StringComparison.CurrentCultureIgnoreCase);
public override bool Equals(object? obj) => obj is LanguageCode other && Equals(other);
public override int GetHashCode() => Value.GetHashCode(StringComparison.CurrentCultureIgnoreCase);
public override string ToString() => Value.ToLower();
public static bool operator ==(LanguageCode left, LanguageCode right) => left.Equals(right);
public static bool operator !=(LanguageCode left, LanguageCode right) => !(left == right);
}
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, sergii.p, Вы писали:
SP>хочется создать новый тип на основе строки, чтобы были запрещены операции сравнения, присваивания к строке. SP>Есть какое-то общепринятое решение? Типа best practice. SP>У меня что-то много boilerplate кода получается
Здравствуйте, sergii.p, Вы писали:
SP>хочется создать новый тип на основе строки, чтобы были запрещены операции сравнения, присваивания к строке. SP>Есть какое-то общепринятое решение? Типа best practice. SP>У меня что-то много boilerplate кода получается
можно такие штуки на F# фигачить(отдельным модулем), будет коротко и смачно https://fsharpforfunandprofit.com/posts/designing-with-types-more-semantic-types/
Здравствуйте, vaa, Вы писали:
vaa>можно такие штуки на F# фигачить(отдельным модулем), будет коротко и смачно
был бы у меня выбор, я бы такие штуки на Rust писал. Ещё короче. Вообще уже стал сомневаться, что такие вещи стоит реализовывать на C#. Многовато кода, а выигрыш не очевиден.
Здравствуйте, sergii.p, Вы писали:
SP>Здравствуйте, vaa, Вы писали:
vaa>>можно такие штуки на F# фигачить(отдельным модулем), будет коротко и смачно
SP>был бы у меня выбор, я бы такие штуки на Rust писал. Ещё короче. Вообще уже стал сомневаться, что такие вещи стоит реализовывать на C#. Многовато кода, а выигрыш не очевиден.
да сила сишарпа в простоте, прямые проверки на нул и т.п. он ближе по духу к лиспу чем к хаскелю.
Здравствуйте, sergii.p, Вы писали: SP>был бы у меня выбор, я бы такие штуки на Rust писал. Ещё короче. Вообще уже стал сомневаться, что такие вещи стоит реализовывать на C#. Многовато кода, а выигрыш не очевиден.
С рекордом кода практически минимум. Как бы, чего ещё?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>С рекордом кода практически минимум. Как бы, чего ещё?
лично для меня не взлетело. Оказалось что проект старый — даже рекорды не поддерживает. Менять версию фреймворка не хочу пока.
К тому же надо подружить с EF, а там ещё кода надо генерить.
В общем, прикинул так: не сейчас.
Здравствуйте, sergii.p, Вы писали:
S>>С рекордом кода практически минимум. Как бы, чего ещё?
SP>лично для меня не взлетело. Оказалось что проект старый — даже рекорды не поддерживает. Менять версию фреймворка не хочу пока. SP>К тому же надо подружить с EF, а там ещё кода надо генерить. SP>В общем, прикинул так: не сейчас.
Если у вас .NET Framework, то с помощью T4 нагенерировать этого вот хоть для тыщи своих типов совсем не сложно:
_FR>partial struct LanguageCode
_FR>{
_FR> public override bool Equals(object? obj) => obj is LanguageCode other && Equals(other);
_FR> public static bool operator ==(LanguageCode left, LanguageCode right) => left.Equals(right);
_FR> public static bool operator !=(LanguageCode left, LanguageCode right) => !(left == right);
_FR>}
Останется вручную определить только типизированный Equals и GetHashCode().
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, sergii.p, Вы писали:
S>>С рекордом кода практически минимум. Как бы, чего ещё?
SP>лично для меня не взлетело. Оказалось что проект старый — даже рекорды не поддерживает. Менять версию фреймворка не хочу пока. SP>К тому же надо подружить с EF, а там ещё кода надо генерить. SP>В общем, прикинул так: не сейчас.
Можно с анонимными классами побаловаться. К ним компилятор тоже генерирует нужные методы.
Можно декомпильнуть и вставить код!
и солнце б утром не вставало, когда бы не было меня