在本类(class)项目中,教师创建了一个用于数据访问的抽象基类 (EfEntityRepositoryBase),这是一个继承抽象基类的每个实体的具体类 (ProductDal)并实现一个接口(interface) (IEntityRepository)。 ProductDal 还有其接口(interface) (IProductDal),它也实现了 IEntityRepository。
这样做的用例是什么? 我无法理解 IProductDal 实现 IEntityRepository 的意义,因为 ProductDal 已经继承了实现相同接口(interface)的抽象基类。因此,如果 IEntityRepository 中有任何函数更新,应该没有问题。如果有人可以解释那就太好了。下面是抽象类和接口(interface)代码。
public class ProductDal : EfEntityRepositoryBase<Product>, IProductDal{ }
public interface IEntityRepository<T>
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
List<T> GetAll(Expression<Func<T, bool>> expression = null);
T GetById(Expression<Func<T, bool>> expression);
}
public interface IProductDal: IEntityRepository<Product>
{
}
public class EfEntityRepositoryBase<TEntity> : IEntityRepository<TEntity> where TEntity : class, IEntity, new()
{
public void Add(TEntity entity)
{
using (BookStoreTrackerDBContext context = new BookStoreTrackerDBContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
}
}
}
最佳答案
我认为很容易理解,当您查看您提供的示例时,很想喊出 IProductDal
。接口(interface)是多余的。事实上,它没有向类型 ProductDal
添加任何额外的成员。因为接口(interface)IProductDal
和通用类 EfEntityRepositoryBase
使用相同的泛型参数类型 Product
进行定义。由于这些教学示例不是在真实的应用程序代码背景下设置的,因此它们背后的真实意图或想法并不容易理解。
作为旁注,您应该知道,如果类 EfEntityRepositoryBase<TEntity>
将使用与 Product
不同的泛型参数类型来定义例如,int
, ProductDal
将有 IEntityRepository<T>
的两个实现/成员重载界面。
例如:
public class ProductDal : EfEntityRepositoryBase<int>, IProductDal
{
// Implementation of IProductDal. The EfEntityRepositoryBase type provides another 'int' overload
public void Add(Product entity) {}
}
void Main()
{
var productDal = new ProductDal();
// Implementation of IEntityRepository<int> provided by class EfEntityRepositoryBase<int>
productDal.Add(6);
// Implementation of 'IProductDal' (provided by class 'ProductDal')
productDal.Add(new Product());
}
您可以看到您提供的示例显示了一种特殊情况,其中 EfEntityRepositoryBase<TEntity>
已经提供了 IEntityRepository<Product>
的实现和 IProductDal 接口(interface)。
回到你的例子:如果你使用类型转换,你会发现另一个使用所谓冗余类型定义的用例:
给定的是你的ProductDal
键入以下类签名
public class ProductDal : EfEntityRepositoryBase<int>, IProductDal
您现在有多种类型可用于访问 IEntityRepository<Product>
的实现
void Main()
{
// Create an instance of ProducDal
ProductDal productDal = new ProductDal();
/* Use the instance of ProductDal with multiple overloads
to show implicit type casting */
UseProductDal(productDal);
UseIProductDal(productDal);
UseIEntityRepository(productDal);
UseEntityRepository(productDal);
}
void UseProductDal(ProductDal productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
}
void UseIProductDal(IProductDal productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
}
void UseIEntityRepository(IEntityRepository<Product> productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
}
void UseEntityRepositoryBase(EntityRepositoryBase<Product> productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
}
这展示了如何使用隐式类型转换以及如何使用接口(interface)。
您现在看到虽然 EntityRepositoryBase<Product>
已经实现 IEntityRepository<Product>
,仍然有ProductDal
另外实现IProductDal
接口(interface)对于启用 ProductDal
非常有意义仅在 IProductDal
的情况下使用接口(interface)是已知的。
您可以利用界面转换来隐藏成员。例如,如果您向每个接口(interface)添加独占成员,则只有在将实现者强制转换为相应的接口(interface)时才能访问该成员:
public interface IEntityRepository<T>
{
void Add(T entity);
}
public interface IProductDal: IEntityRepository<Product>
{
// Exclusive member. Will be only visible when accessed through this interface.
int GetProductCount();
}
给定的是你的ProductDal
键入以下类签名
public class ProductDal : IEfEntityRepository<int>, IProductDal
void Main()
{
// Create an instance of ProducDal
ProductDal productDal = new ProductDal();
/* Use the instance of ProductDal with multiple overloads
to show implicit type casting */
UseProductDal(productDal);
UseIProductDal(productDal);
UseIEntityRepository(productDal);
UseEntityRepository(productDal);
}
// All implemented interfaces are visible since there is no casting involved.
// All members are referenced via the implementor type ProductDal.
void UseProductDal(ProductDal productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
int productCount = productDal.getProductCount();
}
// Only 'IProductDal' is visible since there is an implicit cast to an interface type involved
void UseIProductDal(IProductDal productDal)
{
// Instantiate the argument
var product = new Product();
// 'Add()' is provided by 'IEntityRepository<T>',
// which is implemented by 'IProductDal' and therefore "visible"
productDal.Add(product);
// 'GetProductCount()' is provided by 'IProductDal'
int productCount = productDal.GetProductCount();
}
// Only 'IEntityRepository<T>' is visible since there is an implicit cast to the interface type
void UseIEntityRepository(IEntityRepository<Product> productDal)
{
// Instantiate the argument
var product = new Product();
productDal.Add(product);
// 'GetProductCount()' is only available via the 'IProductDal' interface.
// It's not visible here.
//int productCount = productDal.GetProductCount();
}
关于c# - 同时继承基类和接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69336083/