CA1838: A P/Invokes paramétereinek elkerülése StringBuilder
Tulajdonság | Érték |
---|---|
Szabályazonosító | CA1838 |
Cím | A P/Invokes paramétereinek elkerülése StringBuilder |
Kategória | Teljesítmény |
A javítás kompatibilitástörő vagy nem törik | Nem törés |
Alapértelmezés szerint engedélyezve a .NET 8-ban | Nem |
Ok
A P/Invoke paraméterrel StringBuilder rendelkezik.
Szabály leírása
A StringBuilder
rendezés mindig létrehoz egy natív pufferpéldányt, ami több foglalást eredményez egy P/Invoke híváshoz. P/Invoke paraméterként történő marsallásához StringBuilder
a futtatókörnyezet a következő lesz:
- Natív puffer lefoglalása.
- Ha paraméterről van szó
In
, másolja a tartalmát aStringBuilder
natív pufferbe. - Ha paraméterről van szó
Out
, másolja a natív puffert egy újonnan lefoglalt felügyelt tömbbe.
Alapértelmezés szerint StringBuilder
az és In
Out
a .
További információ a sztringek rendezéséről: Sztringek alapértelmezett rendezése.
Ez a szabály alapértelmezés szerint le van tiltva, mert eseti elemzést igényelhet arról, hogy a szabálysértés érdekes-e, és esetleg nem triviális újrabontást igényel a jogsértés kezeléséhez. A felhasználók a súlyosságuk konfigurálásával explicit módon engedélyezhetik ezt a szabályt.
Szabálysértések kijavítása
A szabálysértések kezelése általában magában foglalja a P/Invoke és a hívók újramunkálását, hogy puffert használjanak ahelyett StringBuilder
. A konkrétumok a P/Invoke használati eseteitől függenek.
Íme egy példa a natív függvény által kitöltendő kimeneti pufferek gyakori forgatókönyvére StringBuilder
:
// Violation
[DllImport("MyLibrary", CharSet = CharSet.Unicode)]
private static extern void Foo(StringBuilder sb, ref int length);
public void Bar()
{
int BufferSize = ...
StringBuilder sb = new StringBuilder(BufferSize);
int len = sb.Capacity;
Foo(sb, ref len);
string result = sb.ToString();
}
Olyan esetekben, amikor a puffer kicsi, és unsafe
a kód elfogadható, a stackalloc használatával lefoglalhatja a puffert a veremen:
[DllImport("MyLibrary", CharSet = CharSet.Unicode)]
private static extern unsafe void Foo(char* buffer, ref int length);
public void Bar()
{
int BufferSize = ...
unsafe
{
char* buffer = stackalloc char[BufferSize];
int len = BufferSize;
Foo(buffer, ref len);
string result = new string(buffer);
}
}
Nagyobb pufferek esetén egy új tömb foglalható le pufferként:
[DllImport("MyLibrary", CharSet = CharSet.Unicode)]
private static extern void Foo([Out] char[] buffer, ref int length);
public void Bar()
{
int BufferSize = ...
char[] buffer = new char[BufferSize];
int len = buffer.Length;
Foo(buffer, ref len);
string result = new string(buffer);
}
Ha a P/Invoke gyakran nagyobb pufferekre van meghívva, ArrayPool<T> akkor a velük járó ismétlődő foglalások és memóriaterhelés elkerülése érdekében használható:
[DllImport("MyLibrary", CharSet = CharSet.Unicode)]
private static extern unsafe void Foo([Out] char[] buffer, ref int length);
public void Bar()
{
int BufferSize = ...
char[] buffer = ArrayPool<char>.Shared.Rent(BufferSize);
try
{
int len = buffer.Length;
Foo(buffer, ref len);
string result = new string(buffer);
}
finally
{
ArrayPool<char>.Shared.Return(buffer);
}
}
Ha a puffer mérete a futtatókörnyezetig nem ismert, előfordulhat, hogy a puffert a méret alapján másképpen kell létrehozni, hogy a nagyméretű pufferek ne legyenek kiosztva a következővel stackalloc
: .
Az előző példák 2 bájt széles karaktereket (CharSet.Unicode
) használnak. Ha a natív függvény 1 bájt karaktert használ (CharSet.Ansi
), byte
puffer helyett char
puffer használható. Például:
[DllImport("MyLibrary", CharSet = CharSet.Ansi)]
private static extern unsafe void Foo(byte* buffer, ref int length);
public void Bar()
{
int BufferSize = ...
unsafe
{
byte* buffer = stackalloc byte[BufferSize];
int len = BufferSize;
Foo(buffer, ref len);
string result = Marshal.PtrToStringAnsi((IntPtr)buffer);
}
}
Ha a paramétert bemenetként is használják, a puffereket fel kell tölteni a sztringadatokkal bármely explicit módon hozzáadott null terminátorsal.
Mikor kell letiltani a figyelmeztetéseket?
Tiltsa le a szabály megsértését, ha nem aggódik a rendezés StringBuilder
teljesítményre gyakorolt hatása miatt.
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 CA1838
// The code that's violating the rule is on this line.
#pragma warning restore CA1838
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.CA1838.severity = none
További információ: Kódelemzési figyelmeztetések letiltása.
Kapcsolódó információk
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: