A public or protected method in a public type has a ref parameter that takes a primitive type, a reference type, or a value type that is not one of the built-in types.
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 that have 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. Passing by value means that the method cannot change the pointer to have it point to a new instance of the reference type, but can change the contents of the object to which it points. For most applications this is sufficient and yields the behavior that you want.
If a method must return a different instance, use the return value of the method to accomplish this. See the System.String class for a variety of methods that operate on strings and return a new instance of a string. By using this model, it is left to the caller to decide whether the original object is preserved.
Although return values are commonplace and heavily used, the correct application of out and ref parameters requires intermediate design and coding skills. Library architects who design for a general audience should not expect users to become proficient in working with out or ref parameters.
Napomena
When you work with parameters that are large structures, the additional resources that are required to copy these structures could cause a performance effect when you pass by value. In these cases, you might consider using ref or out parameters.
How to fix violations
To fix a violation of this rule that is 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 that is caused by a reference type, make sure that the behavior that you want is to return a new instance of the reference. If it is, the method should use its return value to do this.
When to suppress warnings
It is safe to suppress a warning from this rule; however, this design could cause usability issues.
Suppress a warning
If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.
C#
#pragmawarning disable CA1045// The code that's violating the rule is on this line.#pragmawarning restore CA1045
To disable the rule for a file, folder, or project, set its severity to none in the configuration file.
You can configure this option for just this rule, for all rules it applies to, or for all rules in this category (Design) that it applies to. For more information, see Code quality rule configuration options.
Include specific API surfaces
You can configure which parts of your codebase to run this rule on, based on their accessibility, by setting the api_surface option. For example, to specify that the rule should run only against the non-public API surface, add the following key-value pair to an .editorconfig file in your project:
Replace the XXXX part of CAXXXX with the ID of the applicable rule.
Example 1
The following library shows two implementations of a class that generates responses to the feedback of the user. 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#
publicenum Actions
{
Unknown,
Discard,
ForwardToManagement,
ForwardToDeveloper
}
publicenum TypeOfFeedback
{
Complaint,
Praise,
Suggestion,
Incomprehensible
}
publicclassBadRefAndOut
{
// Violates rule: DoNotPassTypesByReference.publicstaticboolReplyInformation(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.publicclassReplyData
{
string reply;
Actions action;
bool returnReply;
// Constructors.publicReplyData()
{
this.reply = String.Empty;
this.action = Actions.Discard;
this.returnReply = false;
}
publicReplyData(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; } }
publicoverridestringToString()
{
return String.Format("Reply: {0} Action: {1} return? {2}",
reply, action.ToString(), returnReply.ToString());
}
}
publicclassRedesignedRefAndOut
{
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;
}
}
Example 2
The following application illustrates the experience of the user. The call to the redesigned library (UseTheSimplifiedClass method) is more straightforward, and the information that is returned by the method is easily managed. The output from the two methods is identical.
C#
publicclassUseComplexMethod
{
staticvoidUseTheComplicatedClass()
{
// 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++;
}
}
staticvoidUseTheSimplifiedClass()
{
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++]);
}
}
publicstaticvoidMain1045()
{
UseTheComplicatedClass();
// Print a blank line in output.
Console.WriteLine("");
UseTheSimplifiedClass();
}
}
Example 3
The following example library illustrates how ref parameters for reference types are used, and shows a better way to implement this functionality.
C#
publicclassReferenceTypesAndParameters
{
// 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.publicstaticvoidBadPassTheObject(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.publicstaticvoidPassTheReference(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.publicstaticstringBetterThanPassTheReference(string argument)
{
return argument + " ABCDE";
}
}
Example 4
The following application calls each method in the library to demonstrate the behavior.
Izvor za ovaj sadržaj možete pronaći na GitHubu, gdje možete stvarati i pregledavati probleme i zahtjeve za povlačenjem. Dodatne informacije potražite u našem vodiču za suradnike.
Povratne informacije o proizvodu .NET
.NET je projekt otvorenog koda. Odaberite vezu za slanje povratnih informacija:
Pridružite se seriji susreta kako biste s kolegama programerima i stručnjacima izgradili skalabilna rješenja umjetne inteligencije temeljena na stvarnim slučajevima upotrebe.