C# 如何在泛型 class 中访问泛型类型的成员?

C# How to access member of generic type in a generic class?

    public class DS2DbContext : DbContext
    {
        public DbSet<DocumentFileData> DocumentFileData { get; set; }
        public DbSet<WatermarkFileData> WatermarkFileData { get; set; }
        public DS2DbContext(DbContextOptions<DS2DbContext> options) 
            : base(options) { }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

    public class FileDataController<T> : ODataController where T : class
    {
        private readonly DS2DbContext _context;
        private readonly ILogger<FileDataController<T>> _logger;

        public FileDataController(DS2DbContext dbContext,
                                  ILogger<FileDataController<T>> logger)
        {
            _logger = logger;
            _context = dbContext;
        }

        [EnableQuery]
        public SingleResult<T> Get([FromODataUri] Guid ID)
        {
            var result = _context.Set<T>().Where(i => i.ID == ID);
            // Error CS1061: 'T' does not contain a definition for 'ID'
            // and no accessible extension method 'ID' accepting a
            // first argument of type 'T' could be found
            return SingleResult.Create(result);
        }
    }

如何正确(如果可能,优雅地)访问类型为 T 的变量成员并获取它们的值?

更新

当我使用这样的界面时:

    public class FileDataController<T> : ODataController where T : IFileData
    {
        private readonly DS2DbContext _context;
        private readonly ILogger<FileDataController<T>> _logger;

        public FileDataController(DS2DbContext dbContext,
                                  ILogger<FileDataController<T>> logger)
        {
            _logger = logger;
            _context = dbContext;
        }

        [EnableQuery]
        public SingleResult<T> Get([FromODataUri] Guid ID)
        {
            var result = _context.Set<T>().Where(i => i.ID == ID);
            // Error CS0452: The type 'T' must be a reference type in
            // order to use it as parameter 'TEntity' in the generic
            // type or method 'DbSet<TEntity>'            
            return SingleResult.Create(result);
        }
    }

调用 _context.Set() 时出现错误。

我想到的是

    var result = _context.Set<T>()
        .Where(x => (Guid) x.GetType().GetProperty("ID").GetValue(x) == ID);

但这看起来非常复杂。

背后的故事

是我必须根据数据的语义(需求文档或水印)将完全相同结构的数据存储在两个不同的数据库中 table。因为我在做 Blazor,首先编码,我需要有两个不同的 classes 才能正确创建两个 tables 并通过两个不同的控制器处理它们。然而,这些控制器共享完全相同的代码和完全相同的底层数据结构。这是一个仅实现 ID 的简化示例:

    public interface IFileData
    {
        public Guid ID { get; set; }
    }

    using System.ComponentModel.DataAnnotations;
    public class FileData : IFileData
    {
        [Key]
        public Guid ID { get; set; } = Guid.Empty;
    }

    public class DocumentFileData : FileData { }

    public class WatermarkFileData : FileData { }

因此,有一个用于 DocumentFileData 的控制器和一个用于 WatermarkFileData 的控制器,可以为每种类型的数据访问适当的数据库 table。但是,所有基础操作都是相同的。所以我希望能够通过一个通用的 class 来解决这个问题,这样我就不必在每次文件数据处理发生变化时对两个不同的 class 进行相同的更改。

正如@GuruSiton 正确评论的那样,您应该在其中引入一个带有 ID 的接口:

interface IClassWithId
{
    Guid ID { get; } // Notice that you only require get - the implementer can choose how the ID get init'd - private / c'tor / etc
}

public class FileDataController<T> : ODataController where T : IClassWithId
{ ... }

这假设您可以制作 - 或要求 - 所有 类 用作 T 来实现 IClassWithId。如果您坚持使用现有的 类 定义自己的 ID 并且无法更改它们,那么您必须求助于反射,正如@NaeemAhmed 所暗示的那样。

因为你有一个公共接口公开 ID 属性 提供相应的泛型约束 - (你需要指定泛型类型约束 - 接口和 class):

public class FileDataController<T> : ODataController where T : class, IFileData