我定义了以下接口:
IDbContext
public interface IDbContext<T> : IDisposable where T : class
{
DbSet<T> Set<T>();
int SaveChanges();
}
由TestContext间接实现,注意TestContext派生自System.Data.Entity.DbContext。
public class TestContext: DbContext,IDbContext<Foo>
{
}
Foo是某个实体
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
编译器抛出以下错误:
类型'T'必须是引用类型才能将其用作形参泛型类型或方法中的'TEntity'"System.Data.Entity。DbSet"TestContext.cs
类型'T'必须是引用类型才能将其用作形参泛型类型或方法中的'TEntity'"System.Data.Entity。DbSet"IDbContext.cs
方法的类型参数"TEntity"的约束'System.Data.Entity.DbContext.Set()'必须匹配接口方法的类型参数"T"的约束"Domain.Logic.Repositories.IDbContext.Set()"。考虑使用显式接口实现。
EntityFramework.dll
当我将约束添加到IDbContext接口中的Generic方法时,错误就会消失:
public interface IDbContext<T> : IDisposable where T : class
{
DbSet<T> Set<T>() where T : class;
int SaveChanges();
}
我很困惑,为什么我需要显式地定义方法上的约束,当它定义在类级别?
根据这些评论,我意识到自己犯了一个错误。
我完全忽略了DbContext.Set()方法上的类型参数。泛型方法的类型参数不同于它的类/接口类型参数(如果有的话),因此应该命名为不同的类型参数。在我的例子中,我有两个问题:1)我有一个泛型接口,具有相同参数名称的泛型类型方法。2)泛型方法本身是在DbContext.Set()之后建模的,DbContext.Set()有自己的约束,但是这些约束不应用于泛型方法本身。
我选择了选项3,如下面的答案所示:
public interface IDbContext : IDisposable {
DbSet<T> Set<T>() where T : class
int SaveChanges();
}
HTH
在DbSet<T> Set<T>()
中删除Set<T>
中的<T>
或在Set<T>
中给T
一个不同的名称,您应该没问题。否则,您定义的T
与IDbContext<T>
中的T
参数不同。这就是为什么编译器需要第二个约束,它认为这是一个不同的T
。因此,您需要以下两个选项之一。第一:
public interface IDbContext<T> : IDisposable where T : class {
DbSet<T> Set();
int SaveChanges();
}
或
public interface IDbContext<T> : IDisposable where T : class {
DbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
或者,从IDbContext
中删除通用参数:
public interface IDbContext : IDisposable {
DbSet<T> Set<T>() where T : class
int SaveChanges();
}
根据你的意见,后者似乎更符合你的需求。