Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Tulajdonság | Érték |
---|---|
Szabályazonosító | CA1021 |
Cím | Paraméterek mellőzése |
Kategória | Tervezés |
A javítás kompatibilitást sértő vagy nem sértő | Rendkívüli |
Alapértelmezés szerint engedélyezve a .NET 9-ben | Nem |
Ok
Egy nyilvános vagy védett metódus egy nyilvános típusban rendelkezik egy out
paraméterrel.
Ez a szabály alapértelmezés szerint csak külsőleg látható típusokat tekint meg, de ez konfigurálható.
Szabály leírása
A típusok hivatkozással (a out
vagy ref
használatával) történő átadásához tapasztalatra van szükség a mutatókkal, az értéktípusok és a referenciatípusok közötti különbségek megértéséhez, valamint a több visszatérési értékkel rendelkező metódusok kezelésének elsajátításához. Ezenkívül a out
és ref
paraméterek közötti különbséget nem értjük széles körben.
Ha egy referenciatípust "hivatkozással" ad át, a metódus a paraméterrel az objektum egy másik példányát kívánja visszaadni. Referenciatípus hivatkozás alapján történő átadása kettős mutatóként, mutató mutatójaként vagy dupla indirekcióként ismert. Az alapértelmezett hívási konvencióval, amely "érték szerint" van átadva, egy hivatkozástípust használó paraméter már kap egy mutatót az objektumhoz. A mutatót, nem azt az objektumot, amelyre mutat, az érték adja át. Az érték szerinti átadás azt jelenti, hogy a metódus nem módosíthatja úgy a mutatót, hogy az a hivatkozástípus új példányára mutasson. Azonban módosíthatja annak az objektumnak a tartalmát, amelyre mutat. A legtöbb alkalmazás esetében ez elegendő, és a kívánt viselkedést eredményezi.
Ha egy metódusnak egy másik példányt kell visszaadnia, ennek végrehajtásához használja a metódus visszatérési értékét. Nézze meg a System.String osztályt, amely különféle metódusokat kínál, amelyek sztringeken működnek és egy sztring új példányát adják vissza. A modell használatakor a hívónak el kell döntenie, hogy az eredeti objektum megmarad-e.
Bár a visszatérési értékek gyakoriak és gyakran használatosak, a out
és ref
paraméterek helyes alkalmazása középszintű tervezési és programozási készségeket igényel. Az általános közönség számára tervező könyvtár-építészek nem számíthatnak arra, hogy a felhasználók jártasak lesznek a out
vagy ref
paraméterek használatában.
Szabálysértések kijavítása
Az értéktípus által okozott szabály megsértésének kijavításához a metódus visszatérési értékként adja vissza az objektumot. Ha a metódusnak több értéket kell visszaadnia, újratervezheti úgy, hogy az értékeket tartalmazó objektum egyetlen példányát adja vissza.
A hivatkozástípus által okozott szabály megsértésének kijavításához győződjön meg arról, hogy a kívánt viselkedés a hivatkozás egy új példányának visszaadása. Ha igen, a metódusnak ehhez a visszatérési értékét kell használnia.
Mikor kell letiltani a figyelmeztetéseket?
A szabály figyelmeztetésének mellőzése biztonságos. Ez a kialakítás azonban használhatósági problémákat okozhat.
Figyelmeztetés mellőzése
Ha csak egyetlen szabálysértést szeretne letiltani, adjon hozzá előfeldolgozási irányelveket a forrásfájlhoz a szabály letiltásához és újbóli engedélyezéséhez.
#pragma warning disable CA1021
// The code that's violating the rule is on this line.
#pragma warning restore CA1021
Ha le szeretné tiltani egy fájl, mappa vagy projekt szabályát, állítsa annak súlyosságát none
a konfigurációs fájlban.
[*.{cs,vb}]
dotnet_diagnostic.CA1021.severity = none
További információ: Kódelemzési figyelmeztetések letiltása.
Kód konfigurálása elemzéshez
A következő beállítással konfigurálhatja, hogy a kódbázis mely részein futtassa ezt a szabályt.
Ezt a beállítást konfigurálhatja csak ehhez a szabályhoz, az összes szabályhoz, vagy az ebben a kategóriában (Tervezés) szereplő összes szabályhoz, amelyekre vonatkozik. További információ: Kódminőségi szabály konfigurációs beállításai.
Adott API-felületek belefoglalása
A api_surface beállítással konfigurálhatja, hogy a kódbázis mely részein futtassa a szabályt az akadálymentességük alapján. Ha például meg szeretné adni, hogy a szabály csak a nem nyilvános API-felületen fusson, adja hozzá a következő kulcs-érték párot a projekt egyik .editorconfig fájljához:
dotnet_code_quality.CAXXXX.api_surface = private, internal
Jegyzet
Cserélje le a XXXX
CAXXXX
részét a vonatkozó szabály azonosítójára.
1. példa
Az alábbi kódtár egy osztály két implementációját mutatja be, amelyek a felhasználói visszajelzésekre adott válaszokat generálják. Az első implementáció (BadRefAndOut
) arra kényszeríti a kódtár-felhasználót, hogy három visszatérési értéket kezeljen. A második implementáció (RedesignedRefAndOut
) leegyszerűsíti a felhasználói élményt egy tárolóosztály (ReplyData
) egy példányának visszaadásával, amely egyetlen egységként kezeli az adatokat.
public enum Actions
{
Unknown,
Discard,
ForwardToManagement,
ForwardToDeveloper
}
public enum TypeOfFeedback
{
Complaint,
Praise,
Suggestion,
Incomprehensible
}
public class BadRefAndOut
{
// Violates rule: DoNotPassTypesByReference.
public static bool ReplyInformation(TypeOfFeedback input,
out string 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.
public class ReplyData
{
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.
public string Reply { get; }
public Actions Action { get; }
public override string ToString()
{
return String.Format("Reply: {0} Action: {1} return? {2}",
Reply, Action.ToString(), _returnReply.ToString());
}
}
public class RedesignedRefAndOut
{
public static 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;
}
}
2. példa
Az alábbi alkalmazás a felhasználó élményét mutatja be. Az újratervezett kódtár (UseTheSimplifiedClass
metódus) hívása egyszerűbb, és a metódus által visszaadott információk könnyen kezelhetők. A két metódus kimenete azonos.
public class UseComplexMethod
{
static void UseTheComplicatedClass()
{
// Using the version with the ref and out parameters.
// You do not have to initialize an out parameter.
string[] reply = new string[5];
// You must initialize a ref parameter.
Actions[] action = {Actions.Unknown,Actions.Unknown,
Actions.Unknown,Actions.Unknown,
Actions.Unknown,Actions.Unknown};
bool[] disposition = new bool[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: {reply[i]} Action: {action[i]} return? {disposition[i]} ");
i++;
}
}
static void 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++]);
}
}
public static void UseClasses()
{
UseTheComplicatedClass();
// Print a blank line in output.
Console.WriteLine("");
UseTheSimplifiedClass();
}
}
3. példa
Az alábbi példatár bemutatja, hogyan ref
használják a referenciatípusok paramétereit, és jobban szemlélteti ennek a funkciónak a megvalósítását.
public class 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.
public static void BadPassTheObject(string argument)
{
argument += " ABCDE";
}
// The following syntax works, but is considered bad design.
// It reassigns the argument to point to a new instance of string.
// Violates rule DoNotPassTypesByReference.
public static void PassTheReference(ref string argument)
{
argument += " ABCDE";
}
// The following syntax works and is a better design.
// It returns the altered argument as a new instance of string.
public static string BetterThanPassTheReference(string argument)
{
return argument + " ABCDE";
}
}
4. példa
Az alábbi alkalmazás meghívja a kódtár minden metódusát a viselkedés bemutatásához.
public class Test
{
public static void MainTest()
{
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);
}
}
Ez a példa a következő kimenetet hozza létre:
Changing pointer - passed by value:
12345
12345
Changing pointer - passed by reference:
12345
12345 ABCDE
Passing by return value:
12345 ABCDE
Mintamódszerek kipróbálás
A Try<Something> mintát implementáló metódusok, példáulSystem.Int32.TryParse, nem emelik ki ezt a szabálysértést. Az alábbi példa egy olyan struktúrát (értéktípust) mutat be, amely implementálja a metódust System.Int32.TryParse .
public struct Point
{
public Point(int axisX, int axisY)
{
X = axisX;
Y = axisY;
}
public int X { get; }
public int Y { get; }
public override int GetHashCode()
{
return X ^ Y;
}
public override bool Equals(object? obj)
{
if (!(obj is Point))
return false;
return Equals((Point)obj);
}
public bool Equals(Point other)
{
if (X != other.X)
return false;
return Y == other.Y;
}
public static bool operator ==(Point point1, Point point2)
{
return point1.Equals(point2);
}
public static bool operator !=(Point point1, Point point2)
{
return !point1.Equals(point2);
}
// Does not violate this rule
public static bool TryParse(string value, out Point result)
{
// TryParse Implementation
result = new Point(0, 0);
return false;
}
}