如何访问泛型类中的泛型成员?


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);

但是这看起来非常复杂。

背后的故事

是我必须根据数据的语义(需求文档或水印)在两个不同的数据库表中存储完全相同结构的数据。因为我在做Blazor,代码第一,我需要有两个不同的类,使它正确地创建两个表,并通过两个不同的控制器处理它们。然而,这些控制器共享完全相同的代码和完全相同的底层数据结构。下面是一个实现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的控制器来访问每种类型数据的适当数据库表。但是,所有底层操作都是相同的。所以我希望能够通过一个泛型类来解决这个问题,以节省我每次在文件数据处理更改时必须对两个不同类进行相同更改的麻烦。

由于您有一个公开ID属性的公共接口,因此提供相应的泛型约束-(您需要同时指定泛型类型约束-接口和class):

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

正如@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所暗示的那样。

最新更新