【问题标题】:workaround a static method in a generic interface解决通用接口中的静态方法
【发布时间】:2021-01-18 23:29:26
【问题描述】:

我有一个商业模式TodoItem。我有一个 API 可以给我todoitems。因此,我为每个控制器都有一个对应的 TodoItemModel(我们将其命名为 TodoItemDTO)。

TodoItemDTO 类应该能够从TodoItem 业务类加载自身。所以,通常情况下,我们会在TodoItemDTOTodoItemDTO FromTodoItem(TodoItem todoItem) 上编写一个静态方法。

我想为这些类定义一个接口。但不幸的是,我无法在接口中定义静态方法...(注意:我使用最新的 C# 版本,所以,最后,我做了,但我应该定义它...但是每个类应该定义它的静态方法)

这是我尝试过的:

public interface IDtoModel<TBussinesModel, TDtoModel>
{
    TDtoModel FromBusinessModel(TBussinesModel businessObject);
}


public class ToDoItemDTO : IDtoModel<ToDoItem, ToDoItemDTO>
{
    public int Id { get; set; }
    [Required]
    public string Title { get; set; }
    public string Description { get; set; }
    public bool IsDone { get; private set; }

    public ToDoItemDTO FromBusinessModel(ToDoItem businessObject)
    {
        return new ToDoItemDTO()
        {
            Id = businessObject.Id,
            Title = businessObject.Title,
            Description = businessObject.Description,
            IsDone = businessObject.IsDone
        };
    }
}

这里唯一的“问题”是我有一个 class 方法,通常应该是一个 static 方法。

因此,例如,当我定义一个通用控制器时,我需要创建新对象而不需要:

[Route("api/[controller]")]
[ApiController]
public abstract class BaseApiController<TBussinesModel, TDtoModel> : Controller
    where TBussinesModel : BaseEntity
    where TDtoModel : IDtoModel<TBussinesModel, TDtoModel>, new()        
{
    protected readonly IRepository _repository;
    public BaseApiController(IRepository repository) { _repository = repository; }

    [HttpGet("{id:int}")]
    public async Task<IActionResult> GetById(int id)
    {
        var businessObject = await _repository.GetByIdAsync<TBussinesModel>(id);
        // 
        // here bellow, I need to create a new object
        // 
        var dtoObject = (new TDtoModel()).FromBusinessModel(businessObject);
        return Ok(dtoObject);
    }

    [HttpPost]
    public abstract Task<IActionResult> Post([FromBody] TDtoModel item);
}

【问题讨论】:

  • 定义一个包含静态方法实现的抽象类? C# 有局限性。
  • 1) 将该方法设为构造函数。 2)创建一个新的工厂类。 3)创建工厂方法字典。 4)使用反射构建表达式树来调用构造函数.....
  • @JeremyLakeman,用于构造函数;如何在界面中定义?
  • 带有工厂接口的工厂类,如果你真的觉得它会增加代码的可理解性,而不是为了它的复杂性

标签: c# .net asp.net-core generics interface


【解决方案1】:

有很多选择,没有一个是完美的。

就我个人而言,我会先将您的工厂方法变成 DTO 的构造函数;

    public ToDoItemDTO(ToDoItem businessObject)
    {
        Id = businessObject.Id;
        Title = businessObject.Title;
        Description = businessObject.Description;
        IsDone = businessObject.IsDone;
    }

您可以为每个 DTO 定义一个工厂类。您可以使用Activator.CreateInstance 在运行时动态调用构造函数。

或者你可以通过反射定位构造函数,构建一个表达式树并编译它。

    static Func<TBussinesModel, TDtoModel> GetFactory<TBussinesModel, TDtoModel>()
    {
        var p = Expression.Parameter(typeof(TBussinesModel), "p");
        return Expression.Lambda<Func<TBussinesModel, TDtoModel>>(
            Expression.New(
                typeof(TDtoModel).GetConstructor(new Type[] { typeof(TBussinesModel) }),
                p
            ),
            p)
            .Compile();
    }

【讨论】:

  • 我是这种模式的新手......当你说“你可以这个;你可以那个”时,就像“和”或“或”?我的意思是,是句子的替代品还是只是步骤
  • 或者。您需要一些接受业务对象并返回 dto 的“接口”。这可能是与工厂类的实际接口。或者那个“接口”可以是一个代表。或者你可以把一切都当作对象。
猜你喜欢
  • 2010-12-16
  • 1970-01-01
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
  • 2014-06-02
  • 1970-01-01
相关资源
最近更新 更多