【发布时间】:2020-01-27 14:23:03
【问题描述】:
我编写了两个抽象类来表示实体的基类:一个Id 属性是int,另一个允许使用指定Id 属性的类型泛型类型参数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 出来后,我就尝试启用nullable reference types,到目前为止效果很好。
但是,对于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 可以是值类型(例如短、长、System.Guid、...),或 System.String。
这有可能吗?
【问题讨论】:
-
顺便说一句,您可能希望禁止
TId的可空引用,您可以使用where TId : notnull来禁止class Entity : BaseEntity<string?>的使用。
标签: generics c#-8.0 nullable-reference-types