天道酬勤,学无止境

干净的代码 - 输出参数坏吗?(Clean Code - Are output parameters bad?)

问题

我在看以前同事的帖子。 他从一篇文章中引用了一些东西

“在 Clean Code 中,Bob Martin 贬低输出参数,说“一般来说应该避免输出参数。”

我当前的代码库是 C#。 我在一个相当大的应用程序中工作。 它主要以程序风格编写,经常违反 SOLID 原则。 当我有机会时,我经常会将一些违反单一职责原则的方法分解为单独的方法。 有时我会创建带有几个输出参数的方法,如下所示。

var value1 int;
var value2 int;

DoSomeWork(out value1, out value2);

我更喜欢这个而不是创建一个特殊的类型,如果创建了一个类型,它无论如何都不会被重用。 这是可以接受的还是有更好的方法?

回答1

通常应该避免输出参数是正确的。 如果可能(并且合理),最好只返回结果。 使用输出变量为您提供了一个比它必须更复杂的准备 - 调用 - 处理过程。

您不必总是创建用于返回值的新类型。 只要您不需要返回值中组件的特定名称,就可以使用框架中的一些类型:

public Tuple<int, int> CalculateMinMax()

这当然只有在返回值的含义很明显的情况下才有用。 在上面的示例中,这两个值应该是按此顺序计算的最小值和最大值。

如果返回值更复杂,最好为其创建一个类型。 如果它那么复杂,那么使用输出变量也不会产生简单的代码。

回答2

TL:博士; 如果您正在编写高级代码,则不应使用输出参数。

在某些情况下有充分的理由使用输出参数。 例如, int.TryParse是使用输出参数返回第二个值的函数的完美示例。

有人可能会争辩说,这样做的原因是效率,因为它不需要构造一个包装器对象来解析一个整数。

另一方面,如果您编写高级代码,您可能应该使用包装这两个值的类或结构。 如果你正在做的是返回两个值,你可以使用Tuple或写自己的struct ,将几乎没有开销。 我是说几乎没有开销,因为所有对象创建都会有一些开销

如果您正在编写一个需要尽可能快地运行的紧密循环,例如某种解析器,您可能会从使用输出参数中受益更多,而不必分配任何过多的对象。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 我可以清洁repl吗?(Can I clean the repl?)
    问题 我在 repl 控制台中玩了很多代码,我该如何清除它? 我想要一个新的而不重新启动它。 可以做到吗? 回答1 如果你想清除你声明的所有临时变量和函数的当前命名空间,你可以使用这个 liner (或创建一个函数): (map #(ns-unmap *ns* %) (keys (ns-interns *ns*))) 或者 (ns myutil) (defn ns-clean "Remove all internal mappings from a given name space or the current one if no parameter given." ([] (ns-clean *ns*)) ([ns] (map #(ns-unmap ns %) (keys (ns-interns ns))))) (ns mytest) ... make loads of junk ... (myutil/ns-clean) ... great!!! I can now make all new junk ... 它并没有声称给你一个干净整洁的命名空间,只是一个通常在典型的 repl 会话中积累的垃圾更少的命名空间。 小心使用:不要从脚下拉动地毯! 回答2 如果您通过终端窗口(例如:MacOS 上的 Terminal.app 或 Linux 上的 xterm/aterm/urxvt
  • 获取可通过 STDOUT 中的脚本解析的干净的机器友好 Maven 行/xml/json 输出?(Get clean machine-friendly Maven lines/xml/json output parseable by scripts in STDOUT?)
    问题 例如,对于 Maven 项目运行此命令: mvn dependency:list 我从 Maven 需要的只是这两行(从下面的输出中截取): com.example.code_samples.maven_dependencies:direct_library:jar:0.0.1-SNAPSHOT:compile com.example.code_samples.maven_dependencies:indirect_library:jar:0.0.1-SNAPSHOT:compile 有没有办法(CLI --option )在干净的行,xml,json,...中只看到这个请求的信息? 相反,输出看起来更像是非结构化日志。 它没有已知的格式,并且在 STDOUT 中将所有类型的信息混合在一起。 [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] direct_library [INFO] dependent_binary [INFO] indirect_library [INFO] maven_dependencies
  • 如何使用 kAudioUnitSubType_LowShelfFilter 的 kAULowShelfParam_CutoffFrequency 参数来控制 Core Audio 中的低音?(How to use kAULowShelfParam_CutoffFrequency parameter of kAudioUnitSubType_LowShelfFilter which controls bass in Core Audio?)
    问题 在来到我的这个问题之前,你一定已经经历过这个问题。如何使用 kAudioUnitType_Effect 的 kAudioUnitSubType_LowShelfFilter 来控制核心音频中的低音? 缓慢而稳定地为音乐的低音控制做好准备。 但还没有达到我的目标。 现在我知道我必须改变kAULowShelfParam_CutoffFrequency来改变低音。 我在 5 到 7 天之前使用的以下代码。 这段代码可以正确播放音乐,但不能正确改变低音。 看看这个代码片段:- - (void)awakeFromNib { printf("AUGraphController awakeFromNib\n"); mIsPlaying = false; // clear the mSoundBuffer struct memset(&mUserData.soundBuffer, 0, sizeof(mUserData.soundBuffer)); // create the URLs we'll use for source A and B NSString *sourceA = [[NSBundle mainBundle] pathForResource:@"04 - Second Hand Jawaani - [rKmania.com]" ofType:@"mp3"]
  • .NET中的“ out”参数是一件坏事吗?(Are “out” parameters a bad thing in .NET?)
    问题 .NET中的“ out”参数是一件坏事吗? 关于这个话题有什么好的文章/讨论吗? 回答1 好吧,我有一篇关于ref / out做什么的文章-但它没有讨论您是否应该使用它们。 基本上, out参数通常表示您要有效地从方法返回两个结果。 通常这是代码的味道-但是在某些情况下(最著名的是使用TryXXX模式),您确实有充分的理由想要返回两条信息,而将它们封装在一起并没有多大意义。 换句话说,请避免在可能的情况下轻松执行“退出/引用”操作,但是请不要过分地避免它们。 回答2 在大多数情况下,我建议不要使用Out参数。 它们基本上在代码中增加了副作用,并且在调试时可能是一场噩梦。 在MSDN上有一篇关于Out参数的文章,可在这里找到:http://msdn.microsoft.com/zh-cn/library/t3c3bfhx.aspx 回答3 在没有元组的情况下,它们有时是最干净的方法。 我通常讨厌他们。 F#有一些不错的语法糖可以用来处理它们。 与其让我处理out参数,不如将它们视为返回元组的方法。 各种TryParse方法最终返回两个元素元组: let success, value = Int32.TryParse("1234") (* success is true *) (* value is 1234 *) 非常方便,不会让我感到肮脏。 回答4
  • 数据绑定不适用于用户控件的具有依赖属性的自定义属性(输出窗口是干净的)(Data Binding not working for User Control's custom Property with Dependency Property (Output window is clean))
    问题 注意:我没有像 StackOverflow 上的其他类似文章一样对用户控件内部的控件有问题,我有用户控件本身的属性。 我正在制作一个基于 Canvas 的自定义控件,带有一个依赖属性(使用 propdb 模板): public sealed partial class PresentationViewer : Canvas { #region Properties public ISlide PresentationSlide { get { Debug.WriteLine("Get PresentationSlide"); return (ISlide)GetValue(PresentationSlideProperty); } set { Debug.WriteLine("Set PresentationSlide"); SetValue(PresentationSlideProperty, value); this.ShowSlideContent(); } } // Using a DependencyProperty as the backing store for PresentationSlide. This enables animation, styling, binding, etc... public static readonly
  • 输出参数有什么问题?(What's wrong with output parameters?)
    问题 在 SQL 和 C# 中,我从来没有真正喜欢过输出参数。 我也从未在 VB6 中传递参数 ByRef。 关于依靠副作用来完成某件事的事情让我很困扰。 我知道它们是一种解决无法从函数返回多个结果的方法,但 SQL 中的行集或 C# 和 VB 中的复杂数据类型也能正常工作,而且对我来说似乎更能自我记录。 我的想法是否有问题,或者是否有来自权威来源的资源支持我? 您个人对此有何看法,为什么? 对于想要使用可能说服他们使用不同结构的输出参数进行设计的同事,我能说些什么? 编辑:有趣的转折——我问这个问题的输出参数被用来代替返回值。 当返回值为“ERROR”时,调用者应该将其作为异常处理。 我正在这样做,但对这个想法并不满意。 一位同事没有被告知需要处理这种情况,结果,由于程序无声无息地失败,损失了大量资金! 回答1 Bob Martin 写了关于这个 Clean Code 的文章。 输出参数打破了函数的基本思想。 output = someMethod(input) 回答2 输出参数可能是一种代码异味,表明您的方法做得太多了。 如果您需要返回多个值,则该方法可能会做不止一件事。 如果数据紧密相关,那么它可能会受益于包含两个值的类。 当然,情况并非总是如此,但我发现情况通常如此。 换句话说,我认为你应该避免它们。 回答3 他们有自己的位置。 Int32.TryParse 方法是有效使用
  • 截断查询字符串并返回干净的URL C#ASP.net(Truncating Query String & Returning Clean URL C# ASP.net)
    问题 我想使用原始URL,截断查询字符串参数,并返回URL的清理版本。 我希望它可以出现在整个应用程序中,因此通过global.asax执行将是理想的选择。 另外,我认为301重定向也将是有序的。 IE。 网址:www.website.com/default.aspx?utm_source = twitter&utm_medium = social-media 出:www.website.com/default.aspx 实现此目标的最佳方法是什么? 回答1 System.Uri是您的朋友在这里。 它上面有许多有用的实用程序,但您想要的是GetLeftPart: string url = "http://www.website.com/default.aspx?utm_source=twitter&utm_medium=social-media"; Uri uri = new Uri(url); Console.WriteLine(uri.GetLeftPart(UriPartial.Path)); 这给出了输出:http://www.website.com/default.aspx [Uri类确实要求指定协议http://] GetLeftPart基本上说“将uri的左侧部分增加到并包括我指定的部分”。 这可以是Scheme(仅http://位),Authority(www
  • 在Visual Studio中,“清理”命令有什么作用?(In Visual Studio, what does the “Clean” command do?)
    问题 您知道,输出此内容的那个=> ------干净启动:项目:Foo.Bar,配置:调试任何CPU ------ ==========干净:1成功,0失败,0跳过=========== 它在清洗什么? 回答1 输出目录-删除先前构建的代码。 它不会删除bin / obj目录本身(或它们下面的Debug / Release目录),而不会删除实际的.exe,.dll等文件。 不幸的是,这使它对我通常用于清理输出目录的用处不大:当我想压缩源代码时。 由于Clean操作不会执行此操作,因此我通常只直接删除bin和obj目录。 回答2 为什么不找自己呢? 打开Microsoft.Common.Targets(位于%windir%\ Microsoft.NET下),您将看到类似这样的部分: <!-- ============================================================ Clean Delete all intermediate and final build outputs. ============================================================ --> <PropertyGroup> <CleanDependsOn> BeforeClean; CleanReferencedProjects
  • 如何在数组中查找值并使用PHP数组函数将其删除?(How to find a value in an array and remove it by using PHP array functions?)
    问题 如何查找数组中是否存在值,然后将其删除? 删除后,我需要顺序索引顺序。 是否有任何PHP内置数组函数可以执行此操作? 回答1 要搜索数组中的元素,可以使用array_search函数,可以使用unset函数从数组中删除元素。 前任: <?php $hackers = array ('Alan Kay', 'Peter Norvig', 'Linus Trovalds', 'Larry Page'); print_r($hackers); // Search $pos = array_search('Linus Trovalds', $hackers); echo 'Linus Trovalds found at: ' . $pos; // Remove from array unset($hackers[$pos]); print_r($hackers); 您可以参考:https://www.php.net/manual/en/ref.array.php了解更多与数组相关的功能。 回答2 <?php $my_array = array('sheldon', 'leonard', 'howard', 'penny'); $to_remove = array('howard'); $result = array_diff($my_array, $to_remove); ?>
  • python multiprocessing:某些函数完成后不返回(队列内容太大)(python multiprocessing: some functions do not return when they are complete (queue material too big))
    问题 我正在使用多处理的“进程和队列”。 我并行启动了几个函数,大多数函数表现良好:它们完成了,它们的输出进入了Queue,它们显示为.is_alive()== False。 但是由于某些原因,一些功能无法正常工作。 即使函数的最后一行(显示“ Finished”的打印语句)完成后,它们也始终显示.is_alive()== True。 无论我启动的功能集是什么,都会发生这种情况,即使只有一个功能也是如此。 如果不并行运行,则功能正常,并可以正常返回。 什么样的事情可能是什么问题? 这是我用来管理作业的通用功能。 我没有显示的只是传递给它的功能。 它们很长,经常使用matplotlib,有时会启动一些shell命令,但是我无法弄清楚失败的命令的共同点。 def runFunctionsInParallel(listOf_FuncAndArgLists): """ Take a list of lists like [function, arg1, arg2, ...]. Run those functions in parallel, wait for them all to finish, and return the list of their return values, in order. """ from multiprocessing import Process
  • R:从使用RCurl抓取的网页中提取“干净的” UTF-8文本(R: extracting “clean” UTF-8 text from a web page scraped with RCurl)
    问题 我正在尝试使用R刮取网页,以日语将文本保存到文件中。 最终,这需要进行扩展以每天处理数百页。 我已经在Perl中有一个可行的解决方案,但是我试图将脚本迁移到R,以减轻在多种语言之间切换的认知负担。 到目前为止,我没有成功。 相关问题似乎是关于保存csv文件的问题和关于将希伯来语写入HTML文件的问题。 但是,根据那里的答案,我未能成功地将一个解决方案整合到一起。 编辑:关于R的UTF-8输出的此问题也很相关,但尚未解决。 这些页面来自Yahoo! Japan Finance和我的Perl代码如下所示。 use strict; use HTML::Tree; use LWP::Simple; #use Encode; use utf8; binmode STDOUT, ":utf8"; my @arr_links = (); $arr_links[1] = "http://stocks.finance.yahoo.co.jp/stocks/detail/?code=7203"; $arr_links[2] = "http://stocks.finance.yahoo.co.jp/stocks/detail/?code=7201"; foreach my $link (@arr_links){ $link =~ s/"//gi; print("$link\n"); my
  • 如何将参数传递给使用“包含”呈现的 PHP 模板?(How to pass parameters to PHP template rendered with 'include'?)
    问题 在 PHP 模板方面需要您的帮助。 我是 PHP 新手(我来自 Perl+Embperl)。 无论如何,我的问题很简单: 我有一个小模板来呈现一些项目,让它成为一篇博客文章。 我知道使用此模板的唯一方法是使用“包含”指令。 我想在遍历所有相关博客文章的循环中调用此模板。 问题:我需要向这个模板传递一个参数; 在这种情况下,引用表示博客文章的数组。 代码如下所示: $rows = execute("select * from blogs where date='$date' order by date DESC"); foreach ($rows as $row){ print render("/templates/blog_entry.php", $row); } function render($template, $param){ ob_start(); include($template);//How to pass $param to it? It needs that $row to render blog entry! $ret = ob_get_contents(); ob_end_clean(); return $ret; } 任何想法如何实现这一点? 我真的很难过:) 还有其他方法可以呈现模板吗? 回答1 Consider including a PHP
  • 使用Git检查脏索引或未跟踪的文件(Checking for a dirty index or untracked files with Git)
    问题 如何检查git存储库中是否有未提交的更改: 更改已添加到索引中但未提交未跟踪的文件 从脚本? git-status在git版本1.6.4.2中似乎总是返回零。 回答1 很好的时机! 几天前,当我想出了如何将git status信息添加到提示中时,我写了一篇关于这件事的博客文章。 这是我的工作: 对于脏状态: # Returns "*" if the current git branch is dirty. function evil_git_dirty { [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*" } 对于未跟踪的文件(请注意--porcelain标志为git status ,它为您提供了不错的可解析输出): # Returns the number of untracked files function evil_git_num_untracked_files { expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` } 尽管git diff --shortstat更方便,但您也可以使用git status --porcelain获取脏文件: # Get number of files added to
  • 为什么在PHP中使用sprintf函数?(Why use sprintf function in PHP?)
    问题 我正在尝试学习有关PHP函数sprintf()的更多信息,但由于我仍然感到困惑,php.net并没有太大帮助,您为什么要使用它? 看下面我的例子。 为什么使用这个: $output = sprintf("Here is the result: %s for this date %s", $result, $date); 当这样做相同并且更容易编写IMO时: $output = 'Here is the result: ' .$result. ' for this date ' .$date; 我在这里想念什么吗? 回答1 sprintf具有原始printf的所有格式化功能,这意味着您不仅可以在字符串中插入变量值,还可以做更多的事情。 例如,指定数字格式(十六进制,十进制,八进制),小数位数,填充等。 Google for printf,您会发现很多例子。 关于printf的维基百科文章应该可以帮助您入门。 回答2 sprintf有许多用例,但我使用它们的一种方式是通过在数据库中存储这样的字符串:“你好,我的名字是%s”或在PHP类中作为常量。 这样,当我想使用该字符串时,我可以简单地做到这一点: $name = 'Josh'; // $stringFromDB = 'Hello, My Name is %s'; $greeting = sprintf(
  • 如何在Bash中解析命令行参数?(How do I parse command line arguments in Bash?)
    问题 说,我有一个脚本被此行调用: ./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile 或这一个: ./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 在每种情况下(或两者的某种组合) $v , $f和$d都将都设置为true并且$outFile等于/fizz/someOtherFile将采用$outFile方式? 回答1 Bash空格分隔(例如--option argument ) cat >/tmp/demo-space-separated.sh <<'EOF' #!/bin/bash POSITIONAL=() while [[ $# -gt 0 ]] do key="$1" case $key in -e|--extension) EXTENSION="$2" shift # past argument shift # past value ;; -s|--searchpath) SEARCHPATH="$2" shift # past argument shift # past value ;; -l|--lib) LIBPATH="$2" shift # past argument shift # past value ;; -
  • 为什么默认值没有出现在我的 docopt 命令行参数字典中?(Why are defaults not appearing in my command-line argument dictionary from docopt?)
    问题 我一直在尝试使用 docopt 来制作一个简单的 CLI,但由于某种原因,我的默认参数没有出现。 下面是我的测试代码。 我正在使用 github 存储库中最新版本的docopt.py 。 """ Usage: scrappy <path> ... [options] -a --auto Automatically scrape and rename without user interaction. -l --lang Specify language code [default: en]. --scan-individual Evaluate series information individually for each file. -c --cfg User alternate config file [default: ../scrappy.conf] -t --test Test run. Do not modify files. -v --verbose Print verbose output """ from docopt import docopt arguments = docopt(__doc__, version='0.1.0 alpha') print arguments # DEBUG 这是我运行$ scrappy/scrappy.py first
  • 在Bash脚本中引发错误(Raise error in a Bash script)
    问题 我想在Bash脚本中引发错误,显示消息“测试用例失败!!”。 如何在Bash中做到这一点? 例如: if [ condition ]; then raise error "Test cases failed !!!" fi 回答1 这取决于您要将错误消息存储在何处。 您可以执行以下操作: echo "Error!" > logfile.log exit 125 或以下内容: echo "Error!" 1>&2 exit 64 引发异常时,将停止程序的执行。 您还可以使用诸如exit xxx ,其中xxx是您可能要返回到操作系统的错误代码(从0到255)。 这里的125和64只是您可以退出的随机代码。 当您需要向OS指示程序异常停止(例如发生错误)时,您需要传递一个非零的退出代码以exit 。 正如@chepner指出的那样,您可以执行exit 1 ,这将意味着未指定的错误。 回答2 基本错误处理 如果您的测试用例运行程序为失败的测试返回了非零代码,则可以简单地编写: test_handler test_case_x; test_result=$? if ((test_result != 0)); then printf '%s\n' "Test case x failed" >&2 # write error message to stderr exit 1 # or
  • Clean Code - Are output parameters bad?
    I was looking at a former colleagues post. He quoted something from an article "In Clean Code Bob Martin disparages output arguments, saying “In general output arguments should be avoided.” My current code base is C#. I am working in a rather large application. It was written primarily in procedural style often breaking SOLID principles. When I have the opportunity I often will break some of the methods that violate single responsibility principle into separate methods. At times I'll create methods with a couple of output parameters as in the following. var value1 int; var value2 int
  • 可以使用ASP.NET Routing为.ashx(IHttpHander)处理程序创建“干净” URL吗?(Can ASP.NET Routing be used to create “clean” URLs for .ashx (IHttpHander) handlers?)
    问题 我有一些使用普通旧IHttpHandler的REST服务。 我想生成更干净的URL,以便在路径中没有.ashx。 有没有一种使用ASP.NET路由来创建映射到ashx处理程序的路由的方法? 我以前看过以下类型的路线: // Route to an aspx page RouteTable.Routes.MapPageRoute("route-name", "some/path/{arg}", "~/Pages/SomePage.aspx"); // Route for a WCF service RouteTable.Routes.Add(new ServiceRoute("Services/SomeService", new WebServiceHostFactory(), typeof(SomeService))); 尝试使用RouteTable.Routes.MapPageRoute()产生错误(该处理程序不是从Page派生的)。 System.Web.Routing.RouteBase似乎只有两个派生类:用于服务的ServiceRoute和用于MVC的DynamicDataRoute 。 我不确定MapPageRoute()作用(Reflector不显示方法主体,它仅显示“对于跨NGen图像边界内联这种类型的方法,性能至关重要”)。 我看到RouteBase没有密封
  • 带有可选参数的干净 URL 的 mod_rewrite 规则(mod_rewrite rules for clean URLs with optional parameters)
    问题 我有当前的网址: http://domain.com 当您访问此 URL 时,它默认加载: http://domain.com/index.php 在我的 .htaccess 我有: Options +FollowSymLinks RewriteEngine On RewriteRule ^([^/]*)$ /index.php?var1=$1 [L] RewriteRule ^([^/]*)/([^/]*)$ /index.php?var1=$1&var2=$2 [L] RewriteRule ^([^/]*)/([^/]*)/([^/]*)$ /index.php?var1=$1&var2=$2&var3=$3 [L] RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ /index.php?var1=$1&var2=$2&var3=$3&var4=$4 [L] RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/]*)$ /index.php?var1=$1&var2=$2&var3=$3&var4=$4&var5=$5 [L] .htaccess 为所有页面提供 404,所以我确定它是错误的。 我希望能够让以下所有 URLS 工作 http://domian.com/val1/