【发布时间】:2020-09-05 20:31:12
【问题描述】:
这个问题主要不是问题帮助电话,而是邀请开发人员就当代、更先进和更清洁的开发方法进行比较。
在这里,我解释了我是如何解决这个问题的,并向您展示了一个有效的代码示例。无论如何,我对我的解决方案有些怀疑。我真的很想知道大自然是否存在一种更优雅的方式来实现相同的代码优化。
当我有两个不同的控制器时,我从这个问题开始,除了 Items 属性类型之外,它们的响应模型几乎相同。
精度:我们需要为每个控制器提供专用而非共享的响应模型。在我看来,这在将来会有所帮助,因为必须更改唯一一个控制器的响应,而不会对其他控制器产生副作用。
当我有两个不同的控制器,除了 Items 属性类型之外,它们的响应模型基本相同时,我已经从问题开始了。
他们是:
namespace Webapi.Models.File {
public class Response {
public FileItem [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
}
public class FileItem {
...
}
}
namespace Webapi.Models.User {
public class Response {
public UserItem [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
}
public class UserItem {
...
}
}
第一个模型以这种方式填充:
using FileModel = Webapi.Models.File;
private FileModel.Response CreateItemsPage(List<FileModel.FileItem> items, int page) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return null;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
return new FileModel.Response() {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
}
除了输入(List
using UserModel = Webapi.Models.User;
private UserModel.Response CreateItemsPage(List<UserModel.UserItem> items, int page) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return null;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
return new UserModel.Response() {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
}
在我的 webapi 控制器中拥有两个甚至更多的克隆方法并不是一个好的观点,我通过创建两个 ObjectExtensions 方法解决了这个问题。
第一个只是将属性从源对象重新分配给目标对象。两者在逻辑上必须在内部具有相同的属性(名称和类型):
public static TTarget AssignProperties<TTarget, TSource>(this TTarget target, TSource source) {
foreach (var targetProp in target.GetType().GetProperties()) {
foreach (var sourceProp in source.GetType().GetProperties()) {
if (targetProp.Name == sourceProp.Name && targetProp.PropertyType == sourceProp.PropertyType) {
targetProp.SetValue(target, sourceProp.GetValue(source));
break;
}
}
}
return target;
}
第二个接收目标和源对象,在内部创建一个匿名对象,然后使用之前的扩展方法 AssignProperties 将属性重新分配给目标对象(需要这样做,因为无法直接访问通用对象属性):
public static TTarget CreateItemsPage<TTarget, TSource>(this TTarget target, List<TSource> items, int page = 1) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return target;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
var source = new {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
target = target.AssignProperties(source);
return target;
}
这是用法:
...
var items = _filesService.ListAllUserFiles(userId, requestData.SearchText);
if(pages.Count() == 0)
return BadRequest();
return Ok(new FileModel.Response().CreateItemsPage(items, requestData.Page));
...
我们将不胜感激一些代码示例。谢谢!
【问题讨论】:
标签: c# .net generics extension-methods