参数参数有什么不好?

我遇到的情况我认为只能通过使用ref参数来解决。 但是,这意味着当我只需要5%的ref参数提供的function时,将方法更改为始终接受ref参数。

这让我觉得“哇,疯了,必须找到另一种方式”。 我是傻瓜吗? ref参数可能导致哪些问题?

编辑

要求提供进一步的细节,我认为它们与我的要求完全无关,但我们走了。

我想要保存一个新实例(将使用以后可能使用的ID更新)或检索与某些逻辑匹配的现有实例并更新它,保存它然后更改新实例的引用以指向现有的。

代码可能会更清晰:

protected override void BeforeSave(Log entity) { var newLog = entity; var existingLog = (from log in repository.All() where log.Stuff == newLog.Stuff && log.Id != newLog.Id select log).SingleOrDefault(); if (existingLog != null) { // update the time existingLog.SomeValue = entity.SomeValue; // remove the reference to the new entity entity = existingLog; } } // called from base class which usually does nothing before save public void Save(TEntity entity) { var report = validator.Validate(entity); if (report.ValidationPassed) { BeforeSave(entity); repository.Save(entity); } else { throw new ValidationException { Report = report }; } } 

事实上,我只会为基类中的一个子(目前为止)添加它,以防止我使用重载(因为我必须复制Save方法)。 我也有问题,我需要强制他们在这个实例中使用ref版本,否则事情将无法按预期工作。

你能加一个超载吗? 有一个没有ref参数的签名,还有一个签名。

参数参数可能很有用,我很高兴它们存在于C#中,但不应该不加思索地使用它们。 通常,如果方法有效地返回两个值,则将方法拆分为两个部分或将两个值封装在单个类型中会更好。 这些都不包括每一个案例 – 绝对有时候ref是最好的选择。

也许对这个5%的情况使用重载函数并保持其他函数不变。

不必要的ref参数可能导致糟糕的设计模式,但如果您有特定需求,那么这样做没有问题

如果您将.NET Framework作为人们对API期望的晴雨表,请考虑几乎所有String方法都返回修改后的值 ,但保持传递的参数不变。 例如,String.Trim()返回修剪过的String – 它不会修剪作为参数传入的String。

现在,显然,只有当您愿意将返回值放入API时,这才是可行的。 此外,如果您的函数已经返回一个值,则会遇到创建包含原始返回值以及新更改的对象的自定义结构的令人讨厌的可能性。

最终,这取决于您以及如何记录您的API。 我根据自己的经验发现,我的同事程序员倾向于期望我的函数“像.NET Framework函数一样”。 🙂

ref参数本身不会引起问题。 这是该语言的文档function。

然而,它可能会导致社会问题。 具体来说,您的API的客户可能不会期望ref参数,因为它很少见。 您可以修改客户端不期望的引用。

当然你可以争辩说,这是客户的错误,因为你没有阅读你的API规范,这是真的。 但有时候最好减少意外。 编写好的代码不仅仅是遵循规则和记录内容,还包括为人类用户制作一些自然显而易见的东西。

过载不会导致您的应用程序或其设计失效。 只要意图明确记录,就应该没问题。

可以考虑的一件事是通过不同类型的参数减轻您对ref参数的担忧。 例如,考虑一下:

 public class SaveArgs { public SaveArgs(TEntity value) { this.Value = value; } public TEntity Value { get; private set;} public int NewId { get; internal set; } public bool NewIdGenerated { get; internal set; } } 

在您的代码中,您只需传递一个SaveArgs而不是TEntity,以便您可以使用更有意义的信息修改其属性。 (当然,它是一个比我上面设计的更好的类。)但是你不必担心模糊的方法接口,你可以在一个冗长的类中返回你需要的尽可能多的数据。

只是一个想法。

编辑:修复了代码。 我的错。

使用我能想到的ref参数没有任何问题,实际上它们有时非常方便。 我认为他们有时会因为调试而变得糟糕,因为变量的值可能会在代码逻辑中发生变化,有时很难跟踪。 转换到像WebServices这样只能通过“值”的东西就足够了。

我对ref参数的最大问题是它们难以使用类型推断,因为有时必须显式声明用作ref参数的变量的类型。

大多数时候我在TryGet场景中使用ref参数。 一般来说,我已停止在该场景中使用ref,而是通过选项选择使用更具function性的样式方法。

例如。 TryGetValue在字典中切换

 bool TryGetValue(TKey key, out TValue value) 

 Option TryGetValue(TKey key) 

选项可在此处获取: http : //blogs.msdn.com/jaredpar/archive/2008/10/08/functional-c-providing-an-option-part-2.aspx

我在ref参数中看到的最常见的用法是返回多个值。 如果是这种情况,您应该考虑创建一个将所有值作为一个对象返回的类或结构。 如果您仍想使用ref但想要使其成为可选项,请添加函数重载。

ref只是一个工具。 你应该想一想:我正在建造什么是最好的设计模式?

  • 有时候使用重载方法会更好。

  • 其他人会更好地返回自定义类型或元组。

  • 其他人会更好地使用全局变量。

  • 其他人参考将是正确的决定。

如果你的方法在5%的时间内只需要这个ref参数,那么你可能需要打破这个方法。 当然没有更多的细节很难说,但这对我来说就像一个违反单一责任原则的情况。 也许超载会有所帮助。

至于你的问题,我认为传递一个参数作为参考是没有问题的,尽管它不是常见的事情。

这是F#或其他函数式编程语言在返回Tuple值时更好地解决的问题之一。 它的语法更清晰,更简洁。 在我正在阅读F#的书中,它实际上指出使用ref的C#equivelant在C#中执行相同的操作以返回多个参数。

我不知道这是一个不好的做法,还是有一些关于ref参数的潜在“booga booga”,对我来说他们只觉得语法不干净。

具有单个参考参数的返回空白函数对我来说当然很有趣。 如果我正在审查这段代码,我建议重构BeforeSave()以包含对Repository.Save()的调用 – 显然是重命名它。 为什么不只是有一个方法来获取你可能新的实体并保证一切都得到妥善保存? 无论如何,调用者对返回的实体不做任何事情。