在 C# 中,是不是可以重构我的 Post 和 Put 方法以消除代码重复?
Posted
技术标签:
【中文标题】在 C# 中,是不是可以重构我的 Post 和 Put 方法以消除代码重复?【英文标题】:In C#, Is it possible to refactor my Post and Put methods to eliminated code duplication?在 C# 中,是否可以重构我的 Post 和 Put 方法以消除代码重复? 【发布时间】:2020-10-30 02:34:03 【问题描述】:我有以下两种方法:
private string Post(string url, ByteArrayContent content, AuthenticationToken token = null)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new HttpClient();
if (token != null)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Access_token);
return client.PostAsync(url, content)
.Result.Content.ReadAsStringAsync()
.Result;
private string Put(string url, ByteArrayContent content, AuthenticationToken token)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new HttpClient();
if (token != null)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Access_token);
return client.PutAsync(url, content)
.Result.Content.ReadAsStringAsync()
.Result;
如您所见,唯一的区别是一个方法调用PostAsync
,而另一个方法调用PutAsync
。
是否可以编写一个函数,例如:
private string Send(string url, ByteArrayContent content, AuthenticationToken token, String functionName)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new HttpClient();
if (token != null)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Access_token);
return client[sendFunction](url, content)
.Result.Content.ReadAsStringAsync()
.Result;
然后我就可以将其他每个功能变成一个衬里,例如:
private string Post(string url, ByteArrayContent content, AuthenticationToken token = null)
this.Send(url, content, token, "PostAsync");
...如果我能以一种类型安全的方式传递函数或函数名,那就更好了。
【问题讨论】:
类似this? 类似的东西。如果我可以简化消费者方面的参数,这样就更好了,这样它就可以表达成Common(url, content, token, HttpClient.PutAsync)
之类的东西,或者消除每次迭代 url 和内容 3 次的需要。
AFAIK 在 C# 中没有“thiscall delegate”的概念。我认为this 是最大值
@Selvin,为您的帮助喝彩。我想我更喜欢我做得更好一点,但我仍然想看看是否有所改进......我会等一下,看看是否有人比我们中的任何一个都更了解。 ;-)
【参考方案1】:
您可以使用switch
表达式。它在 C#8 中变得出奇地实用。您可以在此处阅读更多内容并找到示例:
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#switch-expressions
更新:考虑使用枚举而不是函数名来使您的代码类型安全。
【讨论】:
为响应干杯,但 Robert Cecil Martin 将 switch 描述为令人憎恶的东西,如果必须使用它,应该深深地埋在代码中。 :-) 我正在寻找一种多态的解决方案,或者至少可以在没有分支逻辑的情况下完成。 但是 Robert Cecil Martin 将 switch 描述为一种可憎的东西,如果必须使用它,应该深深地埋在代码中 ...当你有 @987654323 时,这太有趣了@ 这是最糟糕的,远远的,最糟糕的 我承认这不会带来愉快的阅读,但这是我必须使用的 DSL。我可以提取一些变量,但我想不出任何可以在此上下文中添加有用信息的名称。如果您有更好的方法,请告诉我。\【参考方案2】:进一步研究 Selvin 的回应,我想出了:
private string Post(string url, ByteArrayContent content, AuthenticationToken token = null)
return this.Send(token, (client) => client.PostAsync(url, content));
private string Put(string url, StringContent content, AuthenticationToken token)
return this.Send(token, (client) => client.PutAsync(url, content));
private string Send(AuthenticationToken token, Func<HttpClient, Task<HttpResponseMessage>> sendFunction)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new HttpClient();
if (token != null)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Access_token);
return sendFunction(client)
.Result.Content.ReadAsStringAsync()
.Result;
...这几乎是我想要的,但我仍然需要表达两次“客户”。
C# 是否有任何符号可以让我删除这种冗余?
或者我应该接受它“尽可能好”?
【讨论】:
可以通过使用HttpClient.SendAsync
而不是 PostAsync 和 PutAsync 并仅提供 HttpMethod.Post 或 HttpMethod.Put 作为参数来删除冗余。
@ckuri,这确实比删除冗余更具交易性,因为那时我需要冗余调用添加参数的代码。而且使用 PostAsync 和 PutAsync 更有表现力。【参考方案3】:
我假设由于某种原因您不能使用 async/await
运算符,
您可以像这样减少冗余:
public static class Ext
public static string Finalize(this Task<HttpResponseMessage> httpResponseMessage)
return httpResponseMessage
.Result
.Content
.ReadAsStringAsync()
.Result;
public class Program
private string Post(string url, ByteArrayContent content, AuthenticationToken token = null)
return this.CreateClient(token)
.PutAsync(url, content)
.Finalize();
private string Put(string url, StringContent content, AuthenticationToken token)
return this.CreateClient(token)
.PostAsync(url, content)
.Finalize();
private HttpClient CreateClient(AuthenticationToken token)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using HttpClient client = new HttpClient();
if (token != null)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Value);
return client;
因此,将客户端创建包装在一种方法中,并将 Finalizing 你的异步内容包装到扩展方法中
【讨论】:
我不喜欢静态方法,但这是一种有趣的方法。我不熟悉“this”关键字的这种用法,但我想我理解它。另一方面,我不完全清楚系统如何知道将 Ext 类应用于 .Finalize() 方法?我错过了什么吗? 系统应用 Ext 类,因为它是扩展方法。你可以在这里阅读更多关于它们的信息:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… 如果我理解正确,这类似于其他语言可能称为“特征”或“混合”的东西?但是 C# 是如何知道将扩展类应用到程序类的呢?我没有看到任何明确的声明。还是受 Ext 的可见性控制? static .. (this.. ) 方法(扩展方法)在您使用的 napespace 中应用(当前 od 由using
应用),就像用新方法扩展预定义类型一样以上是关于在 C# 中,是不是可以重构我的 Post 和 Put 方法以消除代码重复?的主要内容,如果未能解决你的问题,请参考以下文章
C#将字典的LINQ查询重构为单个lambda表达式[关闭]
将我的 DAL 代码重构为领域驱动设计或更现代的设计 (C# 3.5)?
python接口自动化-requests库优化重构requests方法