使用SqliteAsyncConnection.Table<T>时required成员的约束冲突问题
问题重现
定义包含required字段的实体类以消除null警告:
public class CategoryTable { public CategoryTable() { } [Column("id")] public required int Id { get; set; } [Column("name")] public required string Name { get; set; } }
编写泛型查询方法时,Table<CategoryTable>()触发CS0310错误:
CategoryTable必须是具有公共无参构造函数的非抽象类型,才能用作泛型类型或方法SQLiteAsyncConnection.Table<T>()的参数T
添加where CategoryTable : class, new()约束后,CS0310解决,但调用await DatabaseConn.GetCategoryAsync<CategoryTable>()时触发CS9040错误:
CategoryTable无法满足泛型类型或方法IDatabaseService.GetCategoryAsync<CategoryTable>()中参数CategoryTable的new()约束,因为CategoryTable包含required成员。
解决方案
1. 在无参构造函数中初始化required字段(C# 11+)
C# 11及以上允许在无参构造函数中为required字段赋值,这样既满足new()约束,又保证required字段不会为null:
public class CategoryTable { public CategoryTable() { Id = 0; // 可根据业务设置数据库默认值 Name = string.Empty; } [Column("id")] public required int Id { get; set; } [Column("name")] public required string Name { get; set; } }
这种方式下,SQLite.NET可以通过无参构造创建实例,同时外部手动创建实例时,required字段的强制初始化要求依然生效。
2. 改用[NotNull]属性替代required(兼容旧版本C#)
如果项目使用C# 10及以下,或者不想修改构造函数,可以启用nullable上下文(#nullable enable),并使用[NotNull]属性标记字段,既避免null警告,又满足new()约束:
#nullable enable public class CategoryTable { public CategoryTable() { } [Column("id")] [NotNull] public int Id { get; set; } [Column("name")] [NotNull] public string Name { get; set; } = string.Empty; }
注意引用类型字段(如string)需要赋默认值(比如string.Empty),否则仍会有null警告;值类型(如int)本身不可为null,配合[NotNull]即可消除警告。
核心原因
SQLite.NET的Table<T>方法要求T拥有公共无参构造函数,而C#中包含required字段的类默认不满足new()约束——因为new()要求可以通过new T()创建有效实例,但required字段未初始化的实例是无效的。只有当无参构造函数显式初始化了所有required字段时,类才满足new()约束。
内容的提问来源于stack exchange,提问作者Shawn Crane

