在 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表达式[关闭]

使用 C# 通过 HTTP POST 发送文件

将我的 DAL 代码重构为领域驱动设计或更现代的设计 (C# 3.5)?

python接口自动化-requests库优化重构requests方法

使用 HttpClient 和 C# 在 post 请求中发送 json

在 C# 中是不是可以使用内部和受保护的成员? [复制]