如何最好地修改和返回C#参数?
我需要一个已经设置了多个属性值的小部件。我需要更改小部件的名称。我倾向于选择3,但我很难解释为什么如何最好地修改和返回C#参数?,c#,return-type,signatures,C#,Return Type,Signatures,我需要一个已经设置了多个属性值的小部件。我需要更改小部件的名称。我倾向于选择3,但我很难解释为什么 publicsvoiddo(小部件){//1 widget.Name=“新名称”; } 公共voiddo(ref小部件){//2 widget.Name=“新名称”; } 公共小部件Do(小部件小部件){//3 widget.Name=“新名称”; 返回控件; } 我想通过一些问题和收集答案来扮演魔鬼代言人的角色,来帮助我解释为什么我会被选项3所吸引 选项1:为什么不修改传入的小部件?您只“返回
publicsvoiddo(小部件){//1
widget.Name=“新名称”;
}
公共voiddo(ref小部件){//2
widget.Name=“新名称”;
}
公共小部件Do(小部件小部件){//3
widget.Name=“新名称”;
返回控件;
}
我想通过一些问题和收集答案来扮演魔鬼代言人的角色,来帮助我解释为什么我会被选项3所吸引
选项1:为什么不修改传入的小部件?您只“返回”了一个对象。为什么不直接使用传入的对象呢
选项2:为什么不返回void?为什么不在签名中说明您将使用指向参数对象本身的实际内存指针呢
选项3:返回的对象与传入的对象相同,这难道不奇怪吗?选项1:这是最常见的方法-如果不想修改引用本身,则不需要引用。确保正确命名方法,以便预期传递的对象确实被修改 选项2:这仅在您想要更改传递的引用本身时有用,即创建新的
小部件
实例或将引用设置为指向现有小部件(如果希望保持实例总数较低(如果它们都具有相同的属性),这可能会很有用,请参见,在这种情况下,通常返回的小部件应该是不可变的,而您将使用工厂)。在您的情况下,这似乎不合适
<强>选项3:,这允许一个流畅的“生成器”方法——也有它的好处,即链接小部件的变化,一些人认为它更具表现力和自文档化。也见
这3个选项之间实际上没有任何功能上的区别。(有差异,只是没有与您的问题相关的差异。)保持简单-使用选项1。
选项1: 很好。这正是我要使用的。你可以改变小部件的内容,但不能改变小部件本身 选项2: 不。不。不。不。你不修改引用本身,所以你不需要使用ref
。如果你修改了引用本身(例如widget=newwidget()
,那么out
/ref
是正确的选择,但根据我的经验,这几乎没有必要
选项3:与选项1类似。但是可以链接到流畅风格的API中。我个人不喜欢这样。我只在返回副本并且保持原始对象不变的情况下使用该签名
但这里最重要的是如何命名方法。名称需要清楚地暗示原始对象发生了变化
在许多情况下,我会选择选项4:使类型不可变并返回一个副本。但是对于明显是实体而不是类似值的小部件,这是没有意义的。我认为选项1和选项3都是可行的选项。选项3具有自文档化的优点,因为它意味着您正在修改方法中的小部件。I我认为最糟糕的选项是选项2。对我来说,
ref
关键字意味着你正在修改对象的引用,而你肯定没有这样做。没有更多的上下文,很难有很多意见。@Lance:你的问题、示例和你对每个选项的评论的表述表明你对引用类型在.NET中的行为。例如,在第二个选项中使用ref
完全是多余的。@LBushkin同意。我的理解是,如果我将选项2分配给widget
,而不是它的一个属性,那么选项2会更有趣,但我认为,如图所示,选项2反映了许多用户的困惑开发商(有时可能包括我自己)了解ref
关键字的正确用法。选项1不会修改调用此函数的代码中的小部件,因为它是通过值传递的,而不是通过引用传递的。@David如果小部件是引用类型,它将修改小部件的内容。您所说的仅适用于结构/值类型以及创建wid的人在C#中获取值类型是疯狂的。@David:只有当Widget
是一个结构时,您的语句才是正确的。如果它是一个引用类型(人们通常会假设),那么对Widget
实例的引用将按值传递,允许调用方观察在方法Do()中所做的更改
。你是对的。删除我的原始答案是因为我在那里犯了同样的错误。感谢所有发表评论的人!@CodeInChaos:根据名称小部件的类型来判断OP的合理性并不是很有建设性的-该名称太不具体,无法假设小部件可以不是值类型…但是,可能不是(因为OP没有提到)。然而,鉴于OP对ref
的性质的普遍混淆,可能还有其他一些概念性错误。虽然调用方没有指定,但小部件可能是一个结构。在这种情况下,只有选项2和3才有意义。@LBushkin:确实如此-我发现这不太可能hough-如果是这样的话,他可能还有其他问题。@BrokenGlass您建议使用什么命名约定来设置所传递对象被修改的期望值?@lance:取决于上下文-如何UpdateName()
?但似乎您正在将名称设置为某个固定值?最重要的是(imo)是让它可读的-当您查看方法调用时,您应该能够立即收集它需要的内容