我写了两个抽象类来代表实体的基类:一个是 Id
属性是 整数 , 另一个允许指定 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>
,编译器给出警告:Non-nullable property 'Id' is uninitialized. Consider declaring the property as nullable.
我理解这个警告,但我似乎无法为我的用例解决这个问题。更具体地说,我想允许声明派生自的类型:
System.String
,即 BaseEntity<string>
BaseEntity<System.Guid>
或自定义结构 由于
System.String
不是值类型,这似乎是不可能的:如果我约束 TId
对于结构( BaseEntity<TId> where TId : struct
),我不能声明 BaseEntity<string>
不再。到目前为止,我发现的唯一解决方案(?)禁用警告,是初始化
Id
属性及其默认值并使用 !
运算符(operator):/// <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
.这有可能吗?
最佳答案
不,没有这样的约束——无论您是否使用可为空的引用类型。
您可能会做的是使用私有(private)构造函数来确保只有在基类型中声明的类型才能从 BaseEntity
派生。 ,然后使用两个特定版本:
public abstract class BaseEntity<TId>
{
public TId Id { get; set; }
private BaseEntity<TId>(Id id) => Id = id;
public class StructEntity<T> : BaseEntity<T> where T : struct
{
public StructEntity() : base(default) {}
}
public class StringEntity : BaseEntity<string>
{
public StringEntity(string id) : base(id) {}
}
}
那仍然可以让您使用
BaseEntity<T>
在大多数地方,但任何时候你想构建一个实体,你都需要在这两者之间进行选择。我不知道这将如何与支持序列化联系起来,尽管我个人还是会避开二进制序列化。
关于generics - 与 C# 8.0 可空引用类型结合时,是否可以为值或字符串类型声明泛型类型约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59933006/