gpt4 book ai didi

c# - 在泛型方法中调用特定实现

转载 作者:太空宇宙 更新时间:2023-11-03 20:54:41 25 4
gpt4 key购买 nike

我目前正在尝试实现一种通用方法,以将来自外部服务的 DTO 调整为我的服务模型,但我遇到了一个问题。首先让我将问题背景化。假设外部服务将以下 DTO 返回到我的应用程序。

public class ExampleDTO
{
public int Field1 { get; set; }
public int Field2 { get; set; }
}

这是我的模型。

public class ExampleModel
{
public int Field1 { get; set; }
public int Field2 { get; set; }
}

如果我想将第一个类应用到我的模型中,我可以简单地编写以下方法:

public ExampleModel Adapt(ExampleDTO source)
{
if (source == null) return null;

var target = new ExampleModel()
{
Field1 = source.Field1,
Field2 = source.Field2
};

return target;
}

现在假设当我们获得 ExampleDTO 的集合时,服务不仅返回 ICollection 类型的集合,还返回以下类:

public class PagedCollectionResultDTO<T>
{
public List<T> Data { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public int Total { get; set; }
}

ExampleDTO 列表出现在数据字段中,页码、页面大小和记录总数出现在其余字段中。

我正在尝试实现一个通用方法来使此类适应我自己的模型,该模型具有相同的结构。我想独立于数据字段的类型 T 执行此操作。

public class PagedCollectionResult<T>
{
public List<T> Data { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public int Total { get; set; }

public PagedCollectionResult() => (Data, Page, PageSize, Total) = (new List<T>(), 0, 0, 0);
}

我尝试了以下方法,尝试将 DTO 分页结果 (S) 调整为模型分页结果 (T):

public PagedCollectionResult<T> Adapt<S,T>(PagedCollectionResultDTO<S> source) 
{
if (source == null) return null;

var target = new PagedCollectionResult<T>();

foreach (var item in source.Data)
target.Data.Add(this.Adapt(item));

target.Page = source.Page;
target.PageSize = source.PageSize;
target.Total = source.Total;

return target;
}

问题是我在行中遇到错误:

target.Data.Add(this.Adapt(item));

它说它不能将 S 转换为 ExampleDTO。如果我在 Adapt 上对 ExampleDTO/ExampleModel 施加限制,这就不再通用了。有没有办法为特定类型调用 Adapt(item) 方法?

这是我完整的 TypeAdapter:

public class TypeAdapter
{
public PagedCollectionResult<T> Adapt<S,T>(PagedCollectionResultDTO<S> source)
{
if (source == null) return null;

var target = new PagedCollectionResult<T>();

foreach (var item in source.Data)
target.Data.Add(this.Adapt(item));

target.Page = source.Page;
target.PageSize = source.PageSize;
target.Total = source.Total;

return target;
}

public ExampleModel Adapt(ExampleDTO source)
{
if (source == null) return null;

var target = new ExampleModel()
{
Field1 = source.Field1,
Field2 = source.Field2
};

return target;
}
}

最佳答案

据我了解,该解决方案分为两部分,它们应该相互独立工作。

A 部分:对象转换的通用模式

创建一个接口(interface),供所有需要从外部 DTO 进行调整的模型实现。

public interface IExampleModel<S>
{
void Adapt(S source);
}

此接口(interface)仅需要一个Adapt 方法,泛型S 描述了要适应的类型。

现在为您想要从另一种类型改编的每个模型构建一个类。

public class ExampleModel : IExampleModel<ExampleDTO>
{
public int Field1 { get; set; }
public int Field2 { get; set; }

public void Adapt(ExampleDTO source)
{
Field1 = source.Field1;
Field2 = source.Field2;
}
}

您的 TypeAdapter 类:

public class TypeAdapter
{
public PagedCollectionResult<T> Adapt<S,T>(PagedCollectionResultDTO<S> source)
where T: IExampleModel<S>, new()
{
var target = new PagedCollectionResult<T>();
target.Page = source.Page;
target.Page = source.PageSize;
target.Total = source.Total;
target.Data = AdaptList<S,T>(source.Data).ToList();

return target;
}

protected IEnumerable<T> AdaptList<S,T>(IEnumerable<S> sourceList)
where T : IExampleModel<S>, new()
{
foreach (S sourceItem in sourceList)
{
T targetItem = new T();
targetItem.Adapt(sourceItem);
yield return targetItem;
}
}
}

注意 1:此方法不需要 PagedCollectionResult 构造函数。

注意 2:我选择将 Adapt 方法放在每个模型类中,而不是放在 TypeAdapter 中,以满足开闭原则 .这样,当您想要扩展解决方案以接受第二种类型转换时,您无需修改​​任何现有类(即 TypeModifier),而是添加一个新类。

public class ExampleModel2 : IExampleModel<ExampleDTO2>
{
public int Field1 { get; set; }
public int Field2 { get; set; }

public void Adapt(ExampleDTO2 source)
{
Field1 = source.Field1;
Field2 = source.Field2;
}
}

添加此类将扩展解决方案以包含此转换。

当然,如果更适合您的应用,您可以选择自己的方式。

B 部分:服务调用

据我所知,应用程序无法在仅给定源类型的情况下提取目标类型。您必须在服务调用中提供它。您没有描述您的服务调用是什么样的,所以我只会给您一些提示。

如果您的服务电话是这样的,它会起作用:

    public void ServiceCall<S,T>(PagedCollectionResultDTO<S> sourceCollection)
where T : IExampleModel<S>, new()
{
var typeAdapter = new TypeAdapter();
var targetCollection = typeAdapter.Adapt<S,T>(sourceCollection);
}

如果无法在服务调用中传递 T 类型,您可以使用 if 子句来正确定义目标类型:

    public void ServiceCall<S>(PagedCollectionResultDTO<S> sourceCollection)
{
var typeAdapter = new TypeAdapter();
if (typeof(S) == typeof(ExampleDTO))
{
var targetCollection = typeAdapter.Adapt<ExampleDTO, ExampleModel>(sourceCollection as PagedCollectionResultDTO<ExampleDTO>);
}
else if(typeof(S) == typeof(ExampleDTO2))
{
var targetCollection = typeAdapter.Adapt<ExampleDTO2, ExampleModel2>(sourceCollection as PagedCollectionResultDTO<ExampleDTO2>);
}
}

关于c# - 在泛型方法中调用特定实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51733971/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com