Cause: A public or protected method in a public type has an out parameter.
Rule Description
Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Also, the difference between out and ref parameters is not widely understood.
When a reference type is passed "by reference," the method intends to use the parameter to return a different instance of the object. (Passing a reference type by reference is also known as using a double pointer, pointer to a pointer, or double indirection.) Using the default calling convention, which is pass "by value," a parameter that takes a reference type already receives a pointer to the object. The pointer (not the object to which it points) is passed by value, meaning that the method cannot change the pointer to have it point to a new instance of the reference type, but can alter the contents of the object to which it points. For most applications this is sufficient and yields the desired behavior.
If a method needs to return a different instance, use the method's return value to accomplish this. See the System.String class for a wide variety of methods that operate on strings and return a new instance of a string. Using this model, it is left to the caller to decide whether the original object is preserved.
While return values are commonplace and heavily used, the correct application of out and ref parameters requires intermediate design and coding skills. Library architects designing for a general audience should not expect users to master working with out or ref parameters.
How to Fix Violations
To fix a violation of this rule caused by a value type, have the method return the object as its return value. If the method must return multiple values, redesign it to return a single instance of an object that holds the values.
To fix a violation of this rule caused by a reference type, make sure that returning a new instance of the reference is the desired behavior. If it is, the method should use its return value to do so.
When to Exclude Messages
It is safe to exclude a message from this rule; however, this design might cause usability issues.
Example Code
Example
The following library shows two implementations of a class that generates responses to user's feedback. The first implementation (BadRefAndOut) forces the library user to manage three return values. The second implementation (RedesignedRefAndOut) simplifies the user experience by returning an instance of a container class (ReplyData) that manages the data as a single unit.
[C#]
using System; namespace DesignLibrary { publicenum Actions { Unknown, Discard, ForwardToManagement, ForwardToDeveloper } publicenum TypeOfFeedback { Complaint, Praise, Suggestion, Incomprehensible } publicclass BadRefAndOut { // Violates rule: DoNotPassTypesByReference. publicstaticbool ReplyInformation (TypeOfFeedback input, outstring reply, ref Actions action) { bool returnReply =false; string replyText ="Your feedback has been forwarded "+ "to the product manager."; reply = String.Empty; switch (input) { case TypeOfFeedback.Complaint: case TypeOfFeedback.Praise : action = Actions.ForwardToManagement; reply ="Thank you. "+ replyText; returnReply =true; break; case TypeOfFeedback.Suggestion: action = Actions.ForwardToDeveloper; reply = replyText; returnReply =true; break; case TypeOfFeedback.Incomprehensible: default: action = Actions.Discard; returnReply =false; break; } return returnReply; } } // Redesigned version does not use out or ref parameters; // instead, it returns this container type. publicclass ReplyData { string reply; Actions action; bool returnReply; // Constructors. public ReplyData() { this.reply = String.Empty; this.action = Actions.Discard; this.returnReply =false; } public ReplyData (Actions action, string reply, bool returnReply) { this.reply = reply; this.action = action; this.returnReply = returnReply; } // Properties. publicstring Reply { get{ return reply;}} public Actions Action { get{ return action;}} publicoverridestring ToString() { return String.Format("Reply: {0} Action: {1} return? {2}", reply, action.ToString(), returnReply.ToString()); } } publicclass RedesignedRefAndOut { publicstatic ReplyData ReplyInformation (TypeOfFeedback input) { ReplyData answer; string replyText ="Your feedback has been forwarded "+ "to the product manager."; switch (input) { case TypeOfFeedback.Complaint: case TypeOfFeedback.Praise : answer =new ReplyData( Actions.ForwardToManagement, "Thank you. "+ replyText, true); break; case TypeOfFeedback.Suggestion: answer =new ReplyData( Actions.ForwardToDeveloper, replyText, true); break; case TypeOfFeedback.Incomprehensible: default: answer =new ReplyData(); break; } return answer; } } }
The following application illustrates the user's experience. The call to the redesigned library (UseTheSimplifiedClass method) is more straightforward, and the information returned by the method is easily managed. The output from the two methods is identical.
[C#]
using System; using DesignLibrary; namespace TestDesignLibrary { publicclass UseComplexMethod { staticvoid UseTheComplicatedClass() { // Using the version with the ref and out parameters. // You do not have to initialize an out parameter. string[] reply =newstring[5]; // You must initialize a ref parameter. Actions[] action ={Actions.Unknown,Actions.Unknown, Actions.Unknown,Actions.Unknown, Actions.Unknown,Actions.Unknown}; bool[] disposition=newbool[5]; int i =0; foreach(TypeOfFeedback t in Enum.GetValues(typeof(TypeOfFeedback))) { // The call to the library. disposition[i] = BadRefAndOut.ReplyInformation( t, out reply[i], ref action[i]); Console.WriteLine("Reply: {0} Action: {1} return? {2} ", reply[i], action[i], disposition[i]); i++; } } staticvoid UseTheSimplifiedClass() { ReplyData[] answer =new ReplyData[5]; int i =0; foreach(TypeOfFeedback t in Enum.GetValues(typeof(TypeOfFeedback))) { // The call to the library. answer[i] = RedesignedRefAndOut.ReplyInformation(t); Console.WriteLine(answer[i++]); } } publicstaticvoid Main() { UseTheComplicatedClass(); // Print a blank line in output. Console.WriteLine(""); UseTheSimplifiedClass(); } } }
Example
The following example library illustrates how ref parameters for reference types are used, and shows a better way to implement this functionality.
[C#]
using System; namespace DesignLibrary { publicclass ReferenceTypesAndParameters { // The following syntax will not work. You cannot make a // reference type that is passed by value point to a new // instance. This needs the ref keyword. publicstaticvoid BadPassTheObject(string argument) { argument = argument +" ABCDE"; } // The following syntax will work, but is considered bad design. // It reassigns the argument to point to a new instance of string. // Violates rule DoNotPassTypesByReference. publicstaticvoid PassTheReference(refstring argument) { argument = argument +" ABCDE"; } // The following syntax will work and is a better design. // It returns the altered argument as a new instance of string. publicstaticstring BetterThanPassTheReference(string argument) { return argument +" ABCDE"; } } }
The following application calls each of the methods in the library to demonstrate the behavior.
[C#]
using System; using DesignLibrary; namespace TestDesignLibrary { publicclass Test { publicstaticvoid Main() { string s1 ="12345"; string s2 ="12345"; string s3 ="12345"; Console.WriteLine("Changing pointer - passed by value:"); Console.WriteLine(s1); ReferenceTypesAndParameters.BadPassTheObject (s1); Console.WriteLine(s1); Console.WriteLine("Changing pointer - passed by reference:"); Console.WriteLine(s2); ReferenceTypesAndParameters.PassTheReference (ref s2); Console.WriteLine(s2); Console.WriteLine("Passing by return value:"); s3 = ReferenceTypesAndParameters.BetterThanPassTheReference (s3); Console.WriteLine(s3); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix