Информация об изменениях

Сообщение Re: Новый тип на основе строки от 26.01.2023 16:29

Изменено 27.01.2023 13:46 _FRED_

Подкорректировал код рекорда

Re: Новый тип на основе строки
Здравствуйте, 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 record struct LanguageCode
{
  public LanguageCode(string value) => Value = value?.ToLower();

  public static LanguageCode Default { get; } = new LanguageCode("en");

  private string, Value { get; }

  public override string ToString() => Value ?? String.Empty;
}

Тут компилятор вам сам нагенерит тот же код, который я привёл выше.

Я бы постарался бы сделать так, если я правильно понял 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);
}
Re: Новый тип на основе строки
Здравствуйте, 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);
}