![](/img/trans.png)
[英]TypeScript: Equivalent of C#'s Generic Type Constraint for extending class?
[英]C# : Extending Generic class
partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
我的通用存儲庫為TEntity
實現了一組通用的方法
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
我可以訪問
Repository<User>().Get();
許多存儲庫執行相同的操作集,因此它是有益的,但現在我想擴展Repository<User>
以支持一些其他行為。
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
所以我可以像使用存儲庫一樣
Repository<User>().DoMagicFunction();
如何為Some Tentity
擴展相同的泛型類以擴展新行為而不是修改它。
我可以像創建另一個UserRepository
來支持新功能一樣,但訪問者將成為
UserRepository.DoMagicFunction();
但我希望它像
Repository<User>().DoMagicFunction();
您可以使用擴展方法 :
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
因此,這將以一種語法上很好的方式將函數添加到Repository<User>
對象。
如果您不僅要為User
提供支持,還要為User
的子類提供支持 ,您可以使該功能通用:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C#有一個名為Extension Methods的語言功能,你可能在不知道的情況下從.NET框架中使用它們(例如linq擴展方法 )。 在不破壞代碼功能的情況下,使用擴展方法擴展類甚至接口是很常見的。 以下是您案例的示例。
假設您有一個通用的IRepository
接口:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
該接口遵循SOLID原則 , 尤其是O
和I
原則。
現在假設IEntity
看起來像這樣:
public interface IEntity
{
int Id { get; }
}
現在你可以完美地想象一個經常可重用的擴展方法,如下所示:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
以類似的方式,您還可以擴展您的Repository
類
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
您現在可以像這樣使用它:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
您還可以限制擴展方法:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
但是這樣做會破壞它的目的,你可以在Repository<User>
類中實現它。
如果您的系統和體系結構使用依賴注入 ,那么您可能正在向您的消費類注入IRepository<User>
。 因此,我提供的第一個或第二個擴展方法示例最有意義。
如果你想擴展任何存儲庫,你可以像這樣做。
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
對於特定存儲庫(例如,用戶存儲庫),您可以使用類似的過程
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
擴展方法不是可行的方法,因為實現該方法的代碼只能訪問它們擴展的類的公共/內部成員,並且您可能希望存儲庫的DataContext是私有的。
在我看來,您的方法需要稍微改變一下。
如果您將來想要將Delete方法添加到通用存儲庫,但是您有一些永遠不應刪除的實體,該怎么辦? 您最終會得到一個類似於PurchaseOrder
的存儲庫實例,您必須記住它永遠不會調用delete,否則您將不得不創建一個Repository<T>
的后代,如果被調用則拋出InvalidOperationException
。 兩者都是糟糕的實現。
相反,您應該完全刪除您的IRepository<T>
接口。 保留Repository<T>
類,但為只有您需要的方法的每個實體顯式定義存儲庫接口。
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
當您需要在存儲庫中使用其他方法時,將它們添加到您的IPurchaseOrderRepository並創建Repository<T>
的后代
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
擴展方法是這種情況的最佳選擇。
注意:我沒有檢查但你應該檢查依賴注入仍然正常工作。
您可以使用以下代碼進行測試:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.