如何在泛型<T>基类中使用Linq First方法
问题:将WinUI3 MVVM主详情页的删除逻辑迁移到泛型基类
基于泛型<T>的MasterDetailViewModel<T>基类,我实现了派生类HomePageViewModel : MasterDetailViewModel<Tenant>,其中Tenant是带Id主键的数据库实体类。当前删除逻辑(RelayCommand和DeleteCommand_Executed)放在派生类中,我希望将这些代码全部移到基类中。
仅迁移RelayCommand并在基类声明抽象的DeleteCommand_Executed方法,让派生类重写的方式可以正常运行,但直接把DeleteCommand_Executed移到基类时,会出现CS1061错误:'T'未包含'Id'定义,即使指定Items.First<T>(c => c.Id == parm)也无法解决。想了解如何实现将所有删除相关代码移到基类的目标。
相关代码片段
基类声明
public abstract partial class MasterDetailViewModel<T> : ObservableObject { private readonly ObservableCollection<T> items = new(); // ... 其他代码 }
派生类声明
public partial class HomePageViewModel : MasterDetailViewModel<Tenant> { // ... 其他代码 }
Tenant类定义
[Table("tenants")] public partial class Tenant { public string Email { get; set; } public string FirstName { get; set; } [Key] public int Id { get; set; } // ... 其他代码 }
派生类中原有的删除逻辑
[RelayCommand] private void Delete(int param) // param是选中列表项的Id { DeleteCommand_Executed(param); } private void DeleteCommand_Executed(int parm) { if (parm > 0) { var toBeDeleted = Items.First(c => c.Id == parm); // 获取对应Id的记录 DeleteItem(toBeDeleted); // 从数据库删除 } }
解决方案
要让泛型基类识别T的Id属性,需要通过接口约束泛型类型,具体步骤如下:
- 定义包含Id属性的接口
public interface IHasId { int Id { get; } }
- 让Tenant类实现该接口
[Table("tenants")] public partial class Tenant : IHasId { public string Email { get; set; } public string FirstName { get; set; } [Key] public int Id { get; set; } // ... 其他代码 }
- 修改泛型基类的约束
给基类添加泛型约束where T : IHasId,确保T一定包含Id属性,然后将删除逻辑移到基类中:
public abstract partial class MasterDetailViewModel<T> : ObservableObject where T : IHasId { private readonly ObservableCollection<T> items = new(); // ... 其他代码 [RelayCommand] private void Delete(int param) { DeleteCommand_Executed(param); } private void DeleteCommand_Executed(int parm) { if (parm > 0) { var toBeDeleted = Items.First(c => c.Id == parm); DeleteItem(toBeDeleted); } } // 定义抽象方法让派生类实现具体删除逻辑 protected abstract void DeleteItem(T item); }
- 派生类简化实现
现在HomePageViewModel只需实现DeleteItem方法,无需再重复删除命令相关逻辑:
public partial class HomePageViewModel : MasterDetailViewModel<Tenant> { protected override void DeleteItem(Tenant item) { // 在这里编写具体的数据库删除逻辑 } }
通过以上步骤,即可解决CS1061错误,同时将所有删除相关代码迁移到泛型基类中,实现代码复用。
内容的提问来源于stack exchange,提问作者Kev12853
相关产品推荐
相关产品推荐

