【问题标题】:Can this extensionmethod be modified to have a cleaner syntax?可以修改此扩展方法以具有更清晰的语法吗?
【发布时间】:2020-03-06 19:49:17
【问题描述】:

我的领域模型类继承自:

BaseModel<T>

例如:

public partial class WarehouseType : BaseModel<WarehouseType>
{}

我正在尝试将扩展方法添加到 BaseModel 为:

public static class BaseModelExtensionMethods
{
    public static TDto ToDto<TDto, TModel>(this Model.SharedKernel.BaseModel<TModel> model)
    {
        return Globals.mapper.Map<TDto>(model);
    }
}

这就是我使用它的方式:

Model.Inventory.WarehouseType warehouseType = new Model.Inventory.WarehouseType();

warehouseType.ToDto<V1.Messages.WarehouseTypeDto, Model.Inventory.WarehouseType>();

如上面的代码所示,我需要将两种类型(TDto,TModel)传递给ToDto&lt;&gt;扩展方法。

我想知道是否可以以不需要将TModel 传递给ToDto&lt;&gt; 并在方法中获取TModel 类型的方式修改 ToDto 语法,例如根据到调用扩展方法的对象类型?有什么解决方法或魔法可以做这样的事情吗?我需要这个,以便代码变得更干净和更易于使用。

我正在寻找的理想语法如下:

warehouseType.ToDto<V1.Messages.WarehouseTypeDto>();

【问题讨论】:

  • 您可以添加一个虚拟参数来推断TDto 类型,因为您必须推断所有类型或明确指定所有类型。 public static TDto ToDto&lt;TDto, TModel&gt;(this Model.SharedKernel.BaseModel&lt;TModel&gt; model, TDto dummyToInferType) 或者,您可以在 BaseModel&lt;TModel&gt; 上创建 ToDto&lt;TDto&gt; 方法
  • @juharr 我看不出我应该如何调用您提供的方法。也不能像我的问题中的理想语法那样称呼它。
  • @juharr BaseModel 在我的域模型层中,我试图在域模型层之上的 ESB 层内扩展它,而 Dtos 在 ESB 层内,所以我无法从域模型层引用 ESB 层。
  • 是否需要扩展方法?您可以将您的方法添加到 BaseModel 吗?如果您想将代码放在不同的文件中,可以使用部分类。
  • @Alex-TinLe 它不一定是扩展方法,但我希望它是一个。由于 BaseModel 在域模型层内,如果我将此方法添加到 BaseModel 类,那么我需要将 IMapper 注入到域模型层,我更喜欢目前有点难使用的语法,而不是这种 DI 方法。我知道部分类,并且我在域模型层中有它们,但这不是我想要做的。

标签: c# generics extension-methods


【解决方案1】:

你可以试试这个

public class BaseModel { }
public class BaseModel<T> : BaseModel { }

然后为BaseModel创建扩展方法

public static class BaseModelExtensionMethods
{
public static TDto ToDto<TDto>(this Model.SharedKernel.BaseModel model)
{
    return Globals.mapper.Map<TDto>(model);
}
}

【讨论】:

  • 谢谢亚历克斯。它非常简单易用。 :)
  • 很高兴它有帮助。 :)
  • 鉴于Map 必须采用object 参数,难道你不能让ToDto 采用object 参数吗?
【解决方案2】:

C# 不允许对泛型类型或方法的类型参数进行部分评估(或推断)(您可以切换到 F#,这样做)。所以你有几个选择——如果你愿意创建一个中间类来记住推断的类型,你可以选择逐步泛化,或者创建特化,或者你可以不推断类型。

要分步进行,必须将ToDto方法拆成两部分,并使用一个中间类来承载推断类型。调用这个类Toer(另见this answer):

public class Toer<TModel> {
    Model.SharedKernel.BaseModel<TModel> model;

    public Toer(Model.SharedKernel.BaseModel<TModel> model) => this.model = model;
    public TDto Dto<TDto>() => Globals.mapper.Map<TDto>(model);
}

现在,您创建一个返回 Toer 对象的扩展方法:

public static Toer<TModel> To<TModel>(this Model.SharedKernel.BaseModel<TModel> model) => new Toer<TModel>(model);

现在您可以替换旧代码了:

var wtDto = warehouseType.ToDto<WarehouseTypeDto, Model.Inventory.WarehouseType>();

使用新代码:

var wtDto = warehouseType.To().Dto<WarehouseTypeDto>();

或者,您可以为每个可能的TModel 创建专业化:

public static TDto ToDto<TDto>(this Model.SharedKernel.BaseModel<Model.Inventory.WarehouseType> model) => Globals.mapper.Map<TDto>(model);

您可以根据需要使用它。

最后,您可以将映射预编码为相应的 DTO 类型的特化,并使用它们:

public static WarehouseTypeDto ToDto(this Model.SharedKernel.BaseModel<Model.Inventory.WarehouseType> model) => Globals.mapper.Map<WarehouseTypeDto>(model);

【讨论】:

  • 谢谢您,先生,我从您的回答中学到了很多,非常感谢。但是@Alex-TinLe 发布的答案为我提供了我正在寻找的理想语法,并且对我的代码的复杂性和修改最少,而且不需要像你提到的那样为创建专业化而过度工作。所以我要把他的回答标记为接受的答案。
猜你喜欢
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 2012-06-10
  • 2011-11-21
  • 2021-12-25
  • 2013-05-05
  • 2012-10-18
  • 1970-01-01
相关资源
最近更新 更多