Katika 2025, timu ya PVS-Studio imekuwa kikamilifu kuangalia miradi ya C# ya chanzo wazi. Katika mwaka, tuligundua makosa mengi. Kwa hiyo, tumechagua kumi ya kuvutia zaidi kutoka kwa aina hii kubwa. Tunatarajia utaona hii ya pamoja ya kuvutia na ya manufaa. Jinsi ya kukusanya juu? Kuna vigezo kadhaa ambayo msimbo wa mradi unapaswa kukidhi ili kupata nafasi katika orodha yetu ya juu: inatokana na mradi wa chanzo cha wazi; matatizo yalitambuliwa na PVS-Studio; Kodi inaweza kuwa na makosa; Kodi ni ya kuvutia ya kuangalia; Kila makosa ni ya kipekee. Kwa kuwa mara kwa mara tumeweka orodha hizo, tumewakusanya mkusanyiko mkubwa wa makosa ya ajabu. Unaweza kusoma makala kutoka miaka iliyopita hapa: Makosa 10 ya juu ya 2024 Makosa 10 ya juu ya 2023 Makosa 10 ya juu ya 2022 Makosa 10 ya juu ya 2021 Makosa 10 ya juu ya 2020 Makosa 10 ya juu ya 2019 Sasa, hebu tujiingize katika kaburi la kuvutia la makosa ya C # kwa 2025! P.S. Mwandishi wa makala alichagua na kukusanya makosa kulingana na maoni yake ya kibinafsi. Ikiwa unafikiri hii au kwamba bug anastahili mahali pengine, tafadhali usisahau kuacha maoni :) 10 na kujaribu kutafuta. Mchakato wa leo unaanza na makosa yaliyotajwa katika Inaonekana kama .NET 9 ilizinduliwa hivi karibuni, lakini zaidi ya mwezi mmoja uliopita, .NET 10 ilichukua nafasi yake. . Jinsi ya kurekebisha .NET 9 Makala hii Hebu kurudi kwenye uchambuzi: public static void SetAsIConvertible(this ref ComVariant variant, IConvertible value) { TypeCode tc = value.GetTypeCode(); CultureInfo ci = CultureInfo.CurrentCulture; switch (tc) { case TypeCode.Empty: break; case TypeCode.Object: variant = ComVariant.CreateRaw(....); break; case TypeCode.DBNull: variant = ComVariant.Null; break; case TypeCode.Boolean: variant = ComVariant.Create<bool>(....)); break; case TypeCode.Char: variant = ComVariant.Create<ushort>(value.ToChar(ci)); break; case TypeCode.SByte: variant = ComVariant.Create<sbyte>(value.ToSByte(ci)); break; case TypeCode.Byte: variant = ComVariant.Create<byte>(value.ToByte(ci)); break; case TypeCode.Int16: variant = ComVariant.Create(value.ToInt16(ci)); break; case TypeCode.UInt16: variant = ComVariant.Create(value.ToUInt16(ci)); break; case TypeCode.Int32: variant = ComVariant.Create(value.ToInt32(ci)); break; case TypeCode.UInt32: variant = ComVariant.Create(value.ToUInt32(ci)); break; case TypeCode.Int64: variant = ComVariant.Create(value.ToInt64(ci)); break; case TypeCode.UInt64: variant = ComVariant.Create(value.ToInt64(ci)); break; case TypeCode.Single: variant = ComVariant.Create(value.ToSingle(ci)); break; case TypeCode.Double: variant = ComVariant.Create(value.ToDouble(ci)); break; case TypeCode.Decimal: variant = ComVariant.Create(value.ToDecimal(ci)); break; case TypeCode.DateTime: variant = ComVariant.Create(value.ToDateTime(ci)); break; case TypeCode.String: variant = ComVariant.Create(....); break; default: throw new NotSupportedException(); } } Kuingia mode full screen Kuondoka mode full screen Unaweza kuona tatizo? bila shaka ni huko! case TypeCode.Int64: variant = ComVariant.Create(value.ToInt64(ci)); break; case TypeCode.UInt64: variant = ComVariant.Create(value.ToInt64(ci)); break; // <= Kuingia mode full screen Kuondoka mode full screen Maelezo ya Studio ya PvS: Picha hii ilipigwa tokea ktk veranda za moja ya vyumba vya Manyara Serena Lodge. at wa 3139 Natumaini umewapa macho yako mazoezi mazuri, na macho yako ya kutisha hayakuwapa chini. Badala ya Watumiaji wanapaswa kutumia mfumo wa sasa wa Hii inaweza kuwa makosa ya copy-paste. case TypeCode.UInt64 value.ToInt64 ToUInt64() Mstari wa 9: Utambulisho usio sahihi nafasi ya tisa huenda kwa makosa yaliyoelezwa katika : makala kuhusu kuangalia miradi ya Neo na NBitcoin public override string ToString() { var sb = new StringBuilder(); sb.AppendFormat("{1:X04} {2,-10}{3}{4}", Position, OpCode, DecodeOperand()); return sb.ToString(); } Kuingia mode full screen Kuondoka mode full screen Maelezo ya Studio ya PvS: [CWE-685] Muundo usio sahihi. Idadi tofauti ya vipengele vya muundo inatarajiwa wakati wa kuita 'AppendFormat' kazi. vipengele vya muundo si kutumika: {3}, {4}. Arguments not used: 1st. VMInstruction.cs 105 wa 3025 Naomba yaanze kwa Shukrani njia ya kutokuwa na uhakika husababisha kutokuwa na uhakika. Piga simu ambayo ina makosa mawili. ToString sb.AppendFormat Idadi ya maneno ya kuingiza ni chini ya idadi ya wageni katika mstari wa muundo, ambayo inasababisha kipimo. Hata kama tutafuta swali la kwanza kwa kufanana na idadi ya arguments na watetezi wa nafasi, wito bado utaondoa ukomo. Hii ni kwa sababu indexing ya watetezi wa nafasi huanza na 0, sio 1. Hii inamaanisha kwamba thamani ya tano inahitajika kwa watetezi wa nafasi na kiashiria cha 4, ambayo haipo. Sehemu ya 8 - Uvuvi Hata hivyo, makosa yanatokana na : Makala kuhusu jaribio la injini ya biashara ya Lean public override int GetHashCode() { unchecked { var hashCode = Definition.GetHashCode(); var arr = new int[Legs.Count]; for (int i = 0; i < Legs.Count; i++) { arr[i] = Legs[i].GetHashCode(); } Array.Sort(arr); for (int i = 0; i < arr.Length; i++) { hashCode = (hashCode * 397) ^ arr[i]; } return hashCode; } } public override bool Equals(object obj) { .... return Equals((OptionStrategyDefinitionMatch) obj); } Kuingia mode full screen Kuondoka mode full screen PVS-Studio warning: Jina la 'Legs' linatumika katika mbinu ya 'GetHashCode' lakini haipo katika mbinu ya 'Equals'. wa 3192 Mwandishi huyo alifanya uchambuzi wa Angalia juu ya njia, ambayo inajulikana kama upungufu wa , na alijua kwamba haina kutumia mali, ingawa kwa kutegemea juu yake. Utaratibu wa Equals Equals Legs GetHashCode Hebu tuangalie kwa karibu juu ya Njia ya: Equals public bool Equals(OptionStrategyDefinitionMatch other) { .... var positions = other.Legs .ToDictionary(leg => leg.Position, leg => leg.Multiplier); foreach (var leg in other.Legs) // <= { int multiplier; if (!positions.TryGetValue(leg.Position, out multiplier)) { return false; } if (leg.Multiplier != multiplier) { return false; } } return true; } Kuingia mode full screen Kuondoka mode full screen Tafadhali kumbuka kwamba njia iterates juu ya Kwa kila kipengele katika mkusanyiko huo, msimbo unajaribu kupata katika maneno, lakini maneno haya yanatoka kwa Matokeo yake, msimbo utaangalia kama vipengele vya mkusanyiko vinapatikana katika mkusanyiko huo. other.Legs positions other.Legs Tunaweza kurekebisha msimbo kwa kubadilisha kwa katika eneo la marekebisho. other.Legs Legs Sehemu ya 7 - Tricky Equals Mstari wa saba huenda kwa makosa kutoka kwa : Makala juu ya kuangalia ScottPlot public class CoordinateRangeMutable : IEquatable<CoordinateRangeMutable> { .... public bool Equals(CoordinateRangeMutable? other) { if (other is null) return false; return Equals(Min, other.Min) && Equals(Min, other.Min); // <= } public override bool Equals(object? obj) { if (obj is null) return false; if (obj is CoordinateRangeMutable other) return Equals(other); return false; } public override int GetHashCode() { return Min.GetHashCode() ^ Max.GetHashCode(); // <= } } Kuingia mode full screen Kuondoka mode full screen Maoni ya Studio ya PvS: Kipengele cha 'Max' kinatumika katika mbinu ya 'GetHashCode' lakini haipo katika mbinu ya 'Equals'. ScottPlot CoordinateRangeMutable.cs 198 wa 3192 Kuna subexpressions sawa 'Equals(Min, other.Min)' upande wa kulia na wa kulia wa operator '&&'. ScottPlot CoordinateRangeMutable.cs 172 wa 3001 Mchambuzi alitoa tahadhari mbili kwa sehemu hii ya msimbo.Tazama kwa nini hali hii ilitokea. Tutaanza kwa ajili ya Mtaalamu wa uchambuzi anasema kuwa property is used in the njia, lakini si kwa ajili ya Mtazamo: Ikiwa tunaziona juu ya mstari njia, tunaweza kuona kwamba mwingine katika mwili wake.Tunaweza kuona yafuatayo: ya ya Kanuni ya uchunguzi ilionyesha kipande hiki. wa 3192 Max GetHashCode Equals Equals Equals Equals(Min, other.Min) && Equals(Min, other.Min) wa 3001 Bila shaka, moja ya Operesheni inapaswa kuwa Mfano wa. && Equals(Max, other.Max) Kwa hiyo, uchambuzi ni sahihi - Sio kuonekana katika Njia ya Max Equals Mstari wa 6 - Tricks Hili ni kosa ambalo, kama ilivyoelezwa hapo awali, lilifanywa na Mwisho wa nusu ya kwanza ya mzunguko: Makala juu ya kuangalia ScottPlot public static Interactivity.Key GetKey(this Keys keys) { Keys keyCode = keys & ~Keys.Modifiers; // <= Interactivity.Key key = keyCode switch { Keys.Alt => Interactivity.StandardKeys.Alt, // <= Keys.Menu => Interactivity.StandardKeys.Alt, Keys.Shift => Interactivity.StandardKeys.Shift, // <= Keys.ShiftKey => Interactivity.StandardKeys.Shift, Keys.LShiftKey => Interactivity.StandardKeys.Shift, Keys.RShiftKey => Interactivity.StandardKeys.Shift, Keys.Control => Interactivity.StandardKeys.Control, // <= Keys.ControlKey => Interactivity.StandardKeys.Control, Keys.Down => Interactivity.StandardKeys.Down, Keys.Up => Interactivity.StandardKeys.Up, Keys.Left => Interactivity.StandardKeys.Left, Keys.Right => Interactivity.StandardKeys.Right, _ => Interactivity.StandardKeys.Unknown, }; .... } Kuingia mode full screen Kuondoka mode full screen PVS-Studio warning: Nambari isiyoweza kupatikana iligunduliwa. thamani ya 'mahali' iko nje ya kiwango cha maneno ya mechi. ScottPlot.WinForms FormsPlotExtensions.cs 106 V3202 Baadhi ya maadili ya ndani ya Hiyo ni ya ajabu katika mazingira ya sasa.Tazama nini kinaendelea hapa. switch Kwanza, tunapaswa kuangalia thamani zinazohusiana na vipengele vya makosa katika orodha. [Flags] [TypeConverter(typeof(KeysConverter))] [Editor(....)] public enum Keys { /// <summary> /// The bit mask to extract modifiers from a key value. /// </summary> Modifiers = unchecked((int)0xFFFF0000), .... /// <summary> /// The SHIFT modifier key. /// </summary> Shift = 0x00010000, /// <summary> /// The CTRL modifier key. /// </summary> Control = 0x00020000, /// <summary> /// The ALT modifier key. /// </summary> Alt = 0x00040000 } Kuingia mode full screen Kuondoka mode full screen Kisha, hebu kubadilisha kwa binary: Sasa ni wazi kwamba kuunganisha kila moja ya vipengele vya makosa ya orodha. Modifiers Hivyo thamani ilitolewa kwa Inaweza kupatikana kutoka kwa expression. This expression excludes the value from Pamoja na kuwa Hata hivyo, , na ya Pia itakuwa inapatikana kwa sababu Hivyo basi, kwa mujibu wa takwimu hizi ( have a non-zero bit for each non-zero bit of the erroneous enumeration elements). switch keys & ~Keys.Modifiers Keys.Modifiers keys Keys.Modifiers Shift Control Alt Modifiers Modifiers Kutokana na yote haya, tunaweza kuhitimisha kwamba mchanganyiko wa bit ambayo hufanya ya , or Kwa ajili ya Utaratibu wa operesheni haupo. Shift Control Alt keys & ~Keys.Modifiers Jibu linaweza kuwa katika Utekelezaji badala ya thamani ya orodha. switch nafasi ya tano. kila kitu kilichopangwa Top 5 huanza na makosa yaliyotajwa katika : Jinsi ya kurekebisha .NET 9 struct StackValue { .... public override bool Equals(object obj) { if (Object.ReferenceEquals(this, obj)) return true; if (!(obj is StackValue)) return false; var value = (StackValue)obj; return this.Kind == value.Kind && this.Flags == value.Flags && this.Type == value.Type; } } Kuingia mode full screen Kuondoka mode full screen Maelezo ya Studio ya PvS: Kulinganisha mabadiliko ya aina ya thamani na 'ReferenceEquals' ni sahihi kwa sababu 'this' itakuwa boxed. ILImporter.StackValue.cs 164 Maoni ya 3161 ya method takes parameters of the Kwa mfano, wakati mtu anapopata thamani fulani, anapata . The reference created on the heap won't match any other reference. ReferenceEquals Object Mchezo Tangu ni kupitishwa kama hoja ya kwanza, boxes itakuwa kutokea kila wakati Jinsi ya kufanya hivyo, kuangalia kwa njia ya daima kurejea . this Equals ReferenceEquals false Tafadhali kumbuka kuwa tatizo hili halikuathiri jinsi mbinu inavyofanya kazi. Hata hivyo, mtihani unaotumia method was performed to avoid further comparisons if the references were equal. In other words, this is a kind of optimization. In reality, however, the situation is completely opposite: ReferenceEquals Msimbo daima huendesha baada ya cheque; Kila wito kwa Equals husababisha operesheni ya upigaji kura. Ni ya ajabu kwamba analyzer iliyoundwa katika .NET (mstari wa ) pia hupata tatizo hili. Hata hivyo, watengenezaji wa .NET wenyewe hawakuweza kuepuka :) Mwaka wa 2013 Labda sheria hii ilifutwa kwa ajili ya mradi. Kuanzisha mlinzi juu ya mlinzi wa .NET 5. CA2013 Mstari wa 4 Unsubscribing Jambo la nne ni kwamba kuna makosa ya : Makala kuhusu kuangalia MSBuild private static void SubscribeImmutablePathsInitialized() { NotifyOnScopingReadiness?.Invoke(); FileClassifier.Shared.OnImmutablePathsInitialized -= () => NotifyOnScopingReadiness?.Invoke(); } Kuingia mode full screen Kuondoka mode full screen Maelezo ya Studio ya PvS: Function Anonymous inatumika kufuta usajili kutoka 'OnImmutablePathsInitialized' tukio. Hakuna wafanyabiashara watatumika kufuta usajili, kama instance tofauti ya mwakilishi ni kuundwa kwa kila taarifa ya kazi anonim. CheckScopeClassifier.cs 67 Mji wa 3084 Katika kesi hii, kufuta usajili kutoka kwa mwakilishi haina athari kwa sababu kila wakati kazi isiyojulikana inatangazwa, mfano mpya wa mwakilishi ni kuundwa.Kwa matokeo, jaribio la kufuta usajili kutoka kwa mwakilishi huu haina athari iliyotarajiwa. imeandikwa kwa Hata hivyo, usisahau kutoka ambayo haina athari yoyote. OnImmutablePathsInitialized delegate 1 delegate 2 nafasi ya tatu. upungufu wa operesheni So, we've reached the top three. The error from an Tuna nafasi ya tatu ya heshima: makala kuhusu kuangalia miradi ya Neo na NBitcoin public override int Size => base.Size + ChangeViewMessages?.Values.GetVarSize() ?? 0 + 1 + PrepareRequestMessage?.Size ?? 0 + PreparationHash?.Size ?? 0 + PreparationMessages?.Values.GetVarSize() ?? 0 + CommitMessages?.Values.GetVarSize() ?? 0; Enter fullscreen mode Exit fullscreen mode Maelezo ya Studio ya PvS: [CWE-783] Perhaps the '??' operator works in a different way than it was expected. Its priority is lower than priority of other operators in its left part. RecoveryMessage.cs 35 V3123 Mchambuzi huyo aliandika baadhi ya Nimesikia kesi nyingi ambazo kazi za marafiki zangu (maandiko ya blogu, picha na mawazo) yameibwa na waandishi habari wavivu. Mtumiaji ana nafasi ya chini kuliko Hata hivyo, muundo wa tafsiri hii unaonyesha watengenezaji walitarajia kinyume chake. V3123 ?? + Je, utaratibu wa operesheni ni muhimu hapa? ili kujibu swali, hebu tuangalie mfano wa kuongeza subexpression ikiwa ya : ChangeViewMessages null base.Size + ChangeViewMessages?.Values.GetVarSize() ?? 0 Kuingia mode full screen Kuondoka mode full screen Pamoja na kuwa thamani, matokeo ya subexpression ni daima 0 kwa sababu kuongeza ya Matokeo ya . base.Size base.Size null null Kama sisi kuweka katika nguzo, kubadilisha utaratibu wa operesheni, matokeo yatakuwa . ChangeViewMessages?.Values.GetVarSize() ?? 0 base.Size 2nd place. The treacherous pattern The second place goes to an error from an : Makala kuhusu kuangalia Meneja wa Faili protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode) { .... var modeSeparatorWidth = itemCount is not 0 or 1 ? _modesHostGrid.Children[1] is FrameworkElement frameworkElement ? frameworkElement.ActualWidth : 0 : 0; .... } Kuingia mode full screen Kuondoka mode full screen Maelezo ya Studio ya PvS: [CWE-670] Aina ya mantiki ya 'si 0 au 1' inaweza kutofanya kazi kama ilivyotarajiwa. Aina ya 'si' inashughulikiwa tu na maneno ya kwanza kutoka kwa Aina ya 'au'. wa 3207 Hebu tuangalie kwa karibu juu ya part. Already guessed what's the issue? This pattern is redundant. Its second part affects nothing. itemCount is not 0 or 1 Wakati wa kusema "x sio 0 au 1", watu kwa kawaida wanafikiri kwamba x sio 0 wala 1. Hata hivyo, katika C#, utendaji wa operesheni hufanya kazi tofauti— Kwa kweli maana ya Makosa kama hayo yanaweza kusababisha si tu kuachiliwa, lakini pia makosa kama Hata hivyo, suala hili limekuwa likijadiliwa katika Kulingana na majadiliano, au compiler pengine kukamata tatizo hili katika siku zijazo, au ndani ya static uchambuzi itakuwa alama kama tahadhari. x is not 0 or 1 x is (not 0) or 1 NullReferenceException: list is not null or list.Count == 0 Mkutano wa Mstari wa kwanza: Jinsi ya kufanya kazi? Na mshindi ni makosa ya Hatua hii inachukua nafasi ya kwanza kwa sababu ya ufisadi wake. Baadhi ya watengenezaji hawawezi kuzingatia madhara ya kutumia mbinu za utekelezaji wa muda mfupi pamoja na variables zilizopigwa. maelezo yote hapa chini: Makala kuhusu kuangalia injini ya biashara ya Lean public void FutureMarginModel_MarginEntriesValid(string market) { .... var lineNumber = 0; var errorMessageTemplate = $"Error encountered in file " + $"{marginFile.Name} on line "; var csv = File.ReadLines(marginFile.FullName) .Where(x => !x.StartsWithInvariant("#") && !string.IsNullOrWhiteSpace(x)) .Skip(1) .Select(x => { lineNumber++; // <= .... }); lineNumber = 0; // <= foreach (var line in csv) { lineNumber++; // <= .... } } Kuingia mode full screen Kuondoka mode full screen PVS-Studio warning: Kiwango cha 'lineNumber' kilibadilishwa baada ya kurekodiwa katika njia ya LINQ na utekelezaji wa muda mrefu. thamani ya awali haipatikani wakati wa utekelezaji wa njia. FutureMarginBuyingPowerModelTests.cs 720 wa 3219 The Mabadiliko yaliyotumika yanachukuliwa na kuongezeka katika mwanachama ambao unatumwa kwa njia ya LINQ. ni mbinu iliyotolewa, msimbo wa uwakilishi unaendesha wakati wa iterating juu ya mkusanyiko uliotokana, sio wakati ya kuitwa. lineNumber Select Select While iterating over the collection, the variable is also incremented. As a result, each iteration increases Wakati wa kuondoka na ndani ya ambayo inaonekana kuwa ya ajabu. csv lineNumber lineNumber by 2 foreach Tafadhali kumbuka Utaratibu kabla ya Ni uwezekano kwamba watengenezaji walitarajia kwamba variable hii inaweza kuwa na thamani isiyo ya zero kabla ya mzunguko. huanza na nusu, na mahali pekee ambacho kinabadilika kabla ya Kama ilivyoelezwa hapo juu, mwakilishi huendesha wakati wa iteration, sio kabla yake. lineNumber = 0 foreach lineNumber foreach Mwisho wa Hiyo ni! Tumeenda kupitia tahadhari ya kuvutia zaidi kutoka kwa mtazamo wa mwandishi :) Natumaini umepata mkusanyiko huu wa kuvutia na wa kufikiri katika suala la maendeleo ya msimbo. Ikiwa unataka kuangalia kama mradi wako una matatizo sawa, sasa ni wakati wa kutumia uchambuzi wa static. . Link ya Download