.NET 如何解决层之间所需的泛性

.NET how resolve needed genericity between layers

提问人:pietro 提问时间:10/30/2023 更新时间:10/30/2023 访问量:70

问:

我有一个问题,对某些人来说可能微不足道。我正在 .NET 中制作一个应用程序,我试图在其中创建拆分层。应用程序(仅抽象)和 Infrstructure(实现)。我的问题是我想使用 Azure TableClient 来存储 Azure 存储表中的数据。但是,存储方法需要在该实体上实现 ITableEntity 接口。我只是无法在存储方法的应用程序层中声明这一点,因为我将依赖 Azure.Data.Tables,而我不想这样做。我真的不知道如何用这个编写我的界面,然后“覆盖”它,我猜。

应用:

public interface ITableStorage
{
    public Task SaveItemsAsync<T>(IEnumerable<T> entites, string tableName = nameof(T)) where T : ITableEntity; // where T : ITableEntity is problem
}

基础设施:

public async Task SaveItemsAsync<T>(IEnumerable<T> entites, string tableName = nameof(T)) where T : ITableEntity
{
    var tableClient = _tableServiceClient.GetTableClient(tableName);

    ......
}

提前感谢您的建议。

C# .NET Azure-table-storage clean-architecture

评论


答:

1赞 NotFound 10/30/2023 #1

完全基于您希望它实现的目标来构建您的接口,而无需考虑实现。例如

public interface ICustomerService
{
    public Task AddNewCustomerAsync<T>(Customer customer);
}

完成此操作后,添加实现。

public class TableStorageCustomerService : ICustomerService
{
    public async<Task> AddNewCustomerAsync<T>(Customer customer)
    {
        //map your customer class to your table entity
        //save the table entity to your table storage
    }
}

如您所见,界面中根本没有实现细节。由于您只使用 ,因此可以自由地将其映射到服务实现中数据库可能需要的任何类。Customer

评论

0赞 pietro 10/30/2023
谢谢。但我想对我的方法有一些抽象。我不想为每个“实体”新方法编写。有灵魂吗?
0赞 NotFound 10/30/2023
如果你想抽象你的实现,你的接口自然会这样定义。当您的实现更改或创建单元测试时,它还提供了很大的灵活性。如果您担心过多的重复,您还可以创建一个总体服务,就像您现在添加到 such 中一样。TableStorageCustomerServicepublic TableStorageCustomerService(ITableStorage tableStorage)
1赞 JonasH 10/30/2023 #2

解决方案是使用“实体”的多种表示形式。该应用程序使用规范表示,包括方法、逻辑等。然后,将其转换为适合在 Azure 中存储的类型,或存储实体的其他类型。

这确实需要对同一数据进行多次表示,但它确实增加了一些灵活性。如果更改数据模型,则可以保留旧版 Azure 表示形式,以便可以读取旧数据,同时在保存时使用新的实体类型。这类似于数据传输对象的概念。

要进行类型之间的转换,有几个选项:

  1. 使用类型切换
  2. 使用访客模式。这样做的好处是,可以强制为每个应用程序类型创建一个 azure 类型。所以忘记的机会更少。

您可能需要为应用程序端的实体提供一些通用接口,以便编译器可以帮助确保您只保存设计为要保存的对象。

一个非常简单的例子来说明这个想法:

public interface IMyEntity{}
public class MyEntity {};
public interface IEntityStorage{
    void Save(IMyEntity entity);
}

public class MyEntityAzure : ITableEntity {
    public MyEntityAzure(MyEntity entity){
        // copy properties etc.
    }
    public MyEntity ToModel(){
       // Convert back to application entity
    }
}
public class AzureStorage : IEntityStorage{
    private AzureStorage storage;
    public void Save(IMyEntity entity){
        switch(entity){
            case MyEntity  myEntity:
                storage.Save(new MyEntityAzure(myEntity));
                break;
            // All other entity classes
         }
     }
}