Я написал два абстрактных класса, которые представляют базовый класс для сущностей: один, в котором свойство Id
является int , другой, который позволяет указать тип свойства Id
, используя Параметр типа generi c TId
:
/// <summary>
/// Represents the base class for all entities.
/// </summary>
[System.Serializable]
public abstract class BaseEntity
{
/// <summary>
/// Gets or sets the ID of the entity.
/// </summary>
public int Id { get; set; }
}
/// <summary>
/// Represents the base class for all entities that have an ID of type <typeparamref name="TId"/>.
/// </summary>
/// <typeparam name="TId">
/// The type of the <see cref="Id"/> property.
/// </typeparam>
[System.Serializable]
public abstract class BaseEntity<TId>
{
/// <summary>
/// Gets or sets the ID of the entity.
/// </summary>
public TId Id { get; set; }
}
Эти классы определены в базовой сборке, которую я использую почти во всех проектах, над которыми я работаю. С момента выхода C# 8.0 я экспериментировал с включением обнуляемых ссылочных типов , что до сих пор хорошо работало.
Однако в случае BaseEntity<TId>
компилятор выдает предупреждение:
Необнуляемое свойство 'Id' неинициализировано. Подумайте об объявлении свойства как обнуляемого.
Я понимаю предупреждение, но не могу решить проблему в моем случае использования. Более конкретно, я хочу разрешить объявление типов, которые происходят от:
System.String
, то есть BaseEntity<string>
- Любой тип значения, например
BaseEntity<System.Guid>
или пользовательская структура
Поскольку System.String
не является типом значения, это представляется невозможным: если я ограничу TId
структурами (BaseEntity<TId> where TId : struct
), я не смогу объявить BaseEntity<string>
больше.
Единственное решение (?), которое я нашел до сих пор для отключения предупреждения, - это инициализация свойства Id
его значением по умолчанию и использование оператора !
:
/// <summary>
/// Represents the base class for all entities that have an ID of type <typeparamref name="TId"/>.
/// </summary>
/// <typeparam name="TId">
/// The type of the <see cref="Id"/> property.
/// </typeparam>
[System.Serializable]
public abstract class BaseEntity<TId>
{
/// <summary>
/// Gets or sets the ID of the entity.
/// </summary>
public TId Id { get; set; } = default!;
}
Однако я хотел бы прояснить смысл кода: TId
может быть типом значения (например, short, long, System.Guid
, ...), ИЛИ a System.String
.
Возможно ли это как-то?