FxCopAnalyzer-Warnung: Eine Klassenvariable ‚readonly‘ machen, indem man „den Setter entfernt“ – trotz meines Codes mit direkter Zuweisung

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von mrMo.

    FxCopAnalyzer-Warnung: Eine Klassenvariable ‚readonly‘ machen, indem man „den Setter entfernt“ – trotz meines Codes mit direkter Zuweisung

    Hallo,
    ich habe eine Verständnisfrage.


    Genauere Erklärung und Test-Code bei Post #6. Eine noch zu beurteilende Lösung von mir bei Post #15. Nochmal das Problem erläutert bei Post #17.

    VB.NET-Quellcode

    1. Public Property alle_Mitglieder_Liste As List(Of Class_Nutzer)



    Warnung CA2227 Legen Sie "alle_Mitglieder_Liste" als schreibgeschützt fest, indem Sie den Setter für die Eigenschaft entfernen.

    Wie mache ich das?
    Public ReadOnly Property geht nicht, da dann Fehler erscheinen. Logisch, denn die Liste wird in meinem Programm bearbeitet. Manchmal glaub ich, der FxCopAnalyzer sieht nicht, dass die Variable von woanders bearbeitet wird. Wobei ReadOnly bei List(of T) sich nur um die Liste selbst (nicht um den Inhalt) handelt, oder?

    Viele Grüße
    Bartosz

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    so:

    VB.NET-Quellcode

    1. Dim _alle_Mitglieder_Liste As List(Of Class_Nutzer)
    2. Public readonly Property alle_Mitglieder_Liste As List(Of Class_Nutzer)
    3. Get
    4. return _alle_Mitglieder_Liste
    5. End Get
    6. End Property


    Items innerhalb der Liste können trotzdem von außen bearbeitet werden.

    Edit: @Nofear23m ah ja mist. Haha bei dir fehlt auch was. Get/End Get eingebaut.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Hallo

    Wenn du ein Property ReadOnly machst musst du den Getter selbst erstellen und deine Variable auch.

    VB.NET-Quellcode

    1. Private _alle_Mitlgieder_Liste As List(Of Class_Nutzer)
    2. Public ReadOnly Property alle_Mitglieder_Liste As List(Of Class_Nutzer)
    3. Get
    4. Return _alle_Mitlgieder_Liste
    5. End Get


    Edit: @mrMo Aus dem Kopf raus vergisst man leicht was, das kenne ich ;)

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hmm naja, es gab einen Fehler, weil ich später = New List(of ClassNutzer) schrieb. Ich hab mir überlegt, ob es wirklich so sein muss, und ich habe nun Private ReadOnly _alle_Mitglieder_Liste As New List(Of Class_Nutzer) geschrieben. Aber das löst nicht das Problem. Denn ich habe noch mehr Variablen, zum Beispiel

    VB.NET-Quellcode

    1. Public Property NeueListeBitmaps As New List(Of System.Drawing.Bitmap)
    welche später

    VB.NET-Quellcode

    1. Me.NeueListeBitmaps = ListeBitmaps
    bekommen. Ich kann nicht ReadOnly schreiben.

    Edit: Ich habe gerade gesehen, dass es bei den 4 Warnungen diesen Typs immer um eine List(of T) geht, die später immer mit = New List(of T) bekommen. ReadOnly wäre hier also wirklich falsch. (oder nicht?)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Von innerhalb der Klasse musst du auf die internen Variablen wie _alle_Mitlgieder_Liste zugreifen. Die Property selbst ist readonly, was du ja auch wolltest.

    Evtl. glaubst du auch, das readonly was anderes macht als was es wirklich tut. Was hast du denn im Detail vor damit?
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @mrMo Ich habe nun ein schnell geschriebenes, bereinigtes Projekt, was auch diese Warnungen erzeugt, hochgeladen.
    Was hast du denn im Detail vor damit?
    Es geht darum, dass sowohl bei der Public Sub New eine Liste übergeben wird und auf die Klassenvariable geschrieben wird, als auch, dass die Liste später geändert werden kann; siehe Button2. Dort ist nur noch 1 Pfad und 1 Bild statt 2 vorhanden, und diese lokale Liste wird der Klassen-Liste zugewiesen.

    Die Klasse

    VB.NET-Quellcode

    1. Public Class Klasse
    2. Public Property Bilder As List(Of System.Drawing.Bitmap)
    3. Public Property PfadederBilder As List(Of String)
    4. Public Sub New(ByVal uebergebeneBilder As List(Of System.Drawing.Bitmap), ByVal Pfade As List(Of String))
    5. Me.Bilder = uebergebeneBilder
    6. Me.PfadederBilder = Pfade
    7. End Sub
    8. End Class


    Form1.vb

    VB.NET-Quellcode

    1. Public NotInheritable Class Form1
    2. Private ReadOnly Liste_mit_Instanzen As New List(Of Klasse)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. 'Ich schreibe hier schnell etwas zusammen, um es zum Laufen zu kriegen:
    5. Dim Beispielliste As New List(Of Bitmap)
    6. Beispielliste.Add(New Bitmap("C:\Users\Bartosz\bla\20210519_004916 - Kopie skaliert.jpg"))
    7. Beispielliste.Add(New Bitmap("C:\Users\Bartosz\bla\20210111_141648.jpg"))
    8. Dim BeispiellistePfade As New List(Of String)
    9. BeispiellistePfade.Add("C:\Users\Bartosz\bla\20210519_004916 - Kopie skaliert.jpg")
    10. BeispiellistePfade.Add("C:\Users\Bartosz\bla\20210111_141648.jpg")
    11. 'der wichtige Teil:
    12. Liste_mit_Instanzen.Add(New Klasse(Beispielliste, BeispiellistePfade))
    13. End Sub
    14. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    15. 'Ich schreibe hier schnell etwas zusammen, um es zum Laufen zu kriegen:
    16. Dim NeueListeBitmaps As New List(Of Bitmap)
    17. NeueListeBitmaps.Add(New Bitmap("C:\Users\Bartosz\bla\20210519_004916 - Kopie skaliert.jpg"))
    18. Dim NeueListePfade As New List(Of String)
    19. NeueListePfade.Add("C:\Users\Bartosz\bla\20210519_004916 - Kopie skaliert.jpg")
    20. 'der wichtige Teil:
    21. Liste_mit_Instanzen(0).Bilder = NeueListeBitmaps
    22. Liste_mit_Instanzen(0).PfadederBilder = NeueListePfade
    23. End Sub
    24. End Class
    25. [font='arial,helvetica,sans-serif']
    [/font]
    Bilder
    • Screenshot 2021-07-28 210205.png

      22,2 kB, 921×204, 31 mal angesehen

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Bartosz“ ()

    Würde dann der Sub New einen Parameter übergeben der von dort aus in die interne Variable geschrieben wird.

    Kann deine Code nicht anschauen weil ich hier immer nur mit dem Handy schreibe. Muss dir wohl jemand helfen der am PC sitzt.

    Oder machst einfach alles nicht read only wenns für den Anfang noch zu kompliziert ist. Die Warnung sind keine Fehler sondern wohl eher Empfehlungen, die man auch ignorieren kann.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Die Warnungen werden wohl nur angezeigt weil im Code nirgens auf den Setter zugegriffen wird.
    Also...

    Wenn du nun von außen beim Instanziieren (!!) der Klasse den Wert setzen willst dann brauchst du einen Parameter, aber da tust du bist jetzt ja auch nicht, sonst würde die Warnung nicht kommen.
    Da ich gerade zu tun habe kann ich mir das Projekt im Moment auch nicht ansehen, aber du solltest verstehen wie eine Eigenschaft funktioniert und was ReadOnly bedeutet. Wobei das hier das Schlüsselwort im Grunde ja sagt.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    @Nofear23m Was ich weiß: Properties sind ein Ersatz / Platzhalter für die eigentliche Variable, damit diese Private sein kann. Je nachdem, wie man nun den Setter und Getter gestaltet, können zum Beispiel andere Klassen die Variable sehen / nicht sehen und bearbeiten / nicht bearbeiten.
    ReadOnly heißt "nur Lesezugriff", wobei bei einer List(of T) es nur um die Liste selbst geht -- der Inhalt kann bearbeitet werden.
    Hallo

    Ich versuch mal Licht ins dunkel zu bringen.

    Bartosz schrieb:

    Properties sind ein Ersatz / Platzhalter für die eigentliche Variable

    Nicht wirklich, dann bräuchte es keine Properties, Variablen kannste aus ReadOnly machen. Also wozu.

    Folgendes ist eine Eigenschaft in Kurzform:

    VB.NET-Quellcode

    1. Public Property MeineEigenschaft As String


    In Wirklichkeit ist das aber nur eine Erleichterung für den Programmierer, der Compiler macht dann folgendes draus:

    VB.NET-Quellcode

    1. Private _meineEigenschaft As String
    2. Public Property MeinEigenschaft() As String
    3. Get
    4. Return _meineEigenschaft
    5. End Get
    6. Set(ByVal value As String)
    7. _meineEigenschaft = value
    8. End Set
    9. End Property


    Probiers mal, du kannst sogar auf die "versteckte" Variable bei verwendung der kurzen Schreibweise zugreifen:

    Folgendes Kompiliert und funktioniert:

    VB.NET-Quellcode

    1. Public ReadOnly Property TestProp As String
    2. Public Sub MachWas()
    3. _TestProp = "Hallo"
    4. End Sub


    OK, aber wozu? Du hast nun die Freiheit sowohl Getter, als auch Setter zu Manipulieren oder anderen Code darin auszuführen. Beispiel:

    VB.NET-Quellcode

    1. Private _fullName As String
    2. Public Property FullName() As String
    3. Get
    4. Console.WriteLine($"Der Fullname wurde abgerufen. Rückgabe:{_fullName}")
    5. Return _fullName
    6. End Get
    7. Set(ByVal value As String)
    8. Console.WriteLine($"Der Fullname wurde von {_fullName} auf {value} gesetzt")
    9. _fullName = value
    10. Console.WriteLine($"Der Fullname ist nun {_fullName}")
    11. End Set
    12. End Property


    Dann gibt es Einsatzzwecke für ReadOnly Properties wie z.b. wenn ich den vollen Namen einfach aufrufen will:

    VB.NET-Quellcode

    1. Public Property FirstName As String
    2. Public Property LastName As String
    3. Public ReadOnly Property FullName() As String
    4. Get
    5. Return $"{FirstName} {LastName}"
    6. End Get
    7. End Property


    Aber du kannst auch ein Property mit einem Getter und Setter haben welches NICHT ReadOnly ist und trotzdem von außen nicht beschreibbar ist indem du den Setter einfach nicht Public machst. Dann gehts aber trotzdem innerhalb der Klasse:

    VB.NET-Quellcode

    1. Private _meineEigenschaft As String
    2. Public Property MeinEigenschaft() As String
    3. Get
    4. Return _meineEigenschaft
    5. End Get
    6. Private Set(ByVal value As String)
    7. _meineEigenschaft = value
    8. End Set
    9. End Property


    Bartosz schrieb:

    ReadOnly heißt "nur Lesezugriff", wobei bei einer List(of T) es nur um die Liste selbst geht -- der Inhalt kann bearbeitet werden.


    Hierfür gebe es aber auf eine Lösung wenn die Liste nicht geändert werden darf:

    VB.NET-Quellcode

    1. Private _meineListe As List(Of String)
    2. Public ReadOnly Property MeineListe() As IReadOnlyList(Of String)
    3. Get
    4. Return _meineListe
    5. End Get
    6. End Property


    Nun kann die Liste auch nicht Manipuliert werden.

    Hoffe ich konnte etwas Licht ins dunkel bringen. ;)

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    @Nofear23m Schön und ausführlich beschrieben. Klasse das du dir da Zeit für genommen hast. Denke das hilf @Bartosz ein gutes Stück weiter.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    mrMo schrieb:

    Klasse das du dir da Zeit für genommen hast.

    Manches mal wachse ich über mich selbst hinaus. 8o

    Ne, im erst, manche wissen gar nicht wieviel Arbeit das ist. Nicht das tippen, aber sich was zu überlegen um das verständlich rüber zu bringen und "echte" Beispiele zu verwenden damits plausibel wird.
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Zu Listen als KlassenMember: Ja, sollte man zu 99% Readonly machen.
    Inhalte ändern ist meist oder zumindest oft gewünscht und zulässig, aber Schreibzugriff auf den Member selbst ermöglichen, also dass von Aussen sowas passieren kann:

    VB.NET-Quellcode

    1. TheList = Nothing
    wie gesagt: in 99% wird das Fehler verursachen.
    Also Readonly.
    Oft genug braucht man auch keine Property, weil man gar keine weitere Logik in den Setter oder Getter einfrickeln will. Dann tuts ein Feld u.U. genausogut:

    VB.NET-Quellcode

    1. Public ReadOnly MeineListe As New List(Of String)
    und gut ist.
    Aber das gilt jetzt nicht für 99% der Fälle, sondern ich schätze 50-70%.
    Weil nicht nur zum Logik einfrickeln braucht man Properties, sondern auch Serialisierung und v.a. Databinding reagiert auf Properties anders als auf Public Felder.
    Klasse das du dir da Zeit für genommen hast
    @mrMo und @Nofear23m Ich danke euch beiden!
    Ich habe es nun so gemacht:


    VB.NET-Quellcode

    1. Public Class Klasse
    2. Private _PfadederBilder As List(Of String)
    3. Private _Bilder As List(Of Bitmap)
    4. Public Property PfadederBilder As IReadOnlyList(Of String)
    5. Get
    6. Return _PfadederBilder
    7. End Get
    8. Set
    9. _PfadederBilder = CType(Value, List(Of String))
    10. End Set
    11. End Property
    12. Public Property Bilder As IReadOnlyList(Of System.Drawing.Bitmap)
    13. Get
    14. Return _Bilder
    15. End Get
    16. Set
    17. _Bilder = CType(Value, List(Of Bitmap))
    18. End Set
    19. End Property
    20. Public Sub New(ByVal uebergebeneBilder As List(Of System.Drawing.Bitmap), ByVal Pfade As List(Of String))
    21. Me.Bilder = uebergebeneBilder
    22. Me.PfadederBilder = Pfade
    23. End Sub
    24. End Class


    Habt ihr das gemeint? Es funktioniert jedenfalls. Die Warnungen sind weg.

    manche wissen gar nicht wieviel Arbeit das ist. Nicht das tippen, aber sich was zu überlegen um das verständlich rüber zu bringen und "echte" Beispiele zu verwenden damits plausibel wird.
    Ich kenne das. Zu Beginn der Corona-Pandemie habe ich von März 2020 bis Ende Oktober Nachhilfe gegeben. Mathe, Realschulstoff. Manchmal auch Höheres.

    Ja, aber was hat der Compiler nun davon / was habe ich davon? Ich fasse zusammen: 1) Die Liste selbst ist jetzt geschützt. 2) Inhalte ändern geht weiterhin. 3.) noch etwas?


    Aber jetzt kann die Eigenschaft von außen gesetzt werden, das wolltest du doch nicht und ist wie Erfinder schon schrieb nicht ideal.
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Ich wollte, dass mein Code aus Post #6 funktioniert. Und zeitgleich wollte ich die Warnung loswerden (also das Problem lösen). Wie gesagt, einfach auf ReadOnly setzen geht nicht

    Edit: Ich habe etwas bei StackOverflow gefunden. Dort steht, die Warnung des FxCopAnalyzers heißt, man solle den Setter entfernen bzw. eine Liste ReadOnly machen, weil es sich so gehört. Eine Liste brauche keinen Setter. Aber - ich in meinem Projekt - ich brauche einen Setter, weil ich direkt auf die List(of T) zugreife. Wenn jemand andere Codevorschläge hat, gerne her damit. Aber ich werde jetzt nicht in meinem 2000-Zeilen-Projekt irgendetwas riskieren. Beim nächsten Projekt gerne.


    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Bartosz schrieb:

    Edit: Ich habe etwas bei StackOverflow gefunden. Dort steht, die Warnung des FxCopAnalyzers heißt, man solle den Setter entfernen bzw. eine Liste ReadOnly machen, weil es sich so gehört. Eine Liste brauche keinen Setter.
    Faszinierend - das ist ja ganz genau das, was ich auch schon gesagt habe!

    Wenn du meinst, dein Fall gehört zu dem einen Prozent, dass den Setter doch braucht - das bezweifel ich.
    Meist liegt da ein Missverständnis vor.
    Kannst du die Code-Zeile zeigen, die den Setter verwendet?
    So konnte das Aussehen damit von außen nicht drauf zu gegriffen werden kann und nur bei der Istanzierung einmal Parameter über übergeben werden können.

    VB.NET-Quellcode

    1. Public Class Klasse
    2. Private _PfadederBilder As List(Of String)
    3. Private _Bilder As List(Of Bitmap)
    4. Public readonly Property PfadederBilder As IReadOnlyList(Of String)
    5. Get
    6. Return _PfadederBilder
    7. End Get
    8. End Property
    9. Public readonly Property Bilder As IReadOnlyList(Of System.Drawing.Bitmap)
    10. Get
    11. Return _Bilder
    12. End Get
    13. End Property
    14. Public Sub New(ByVal uebergebeneBilder As List(Of System.Drawing.Bitmap), ByVal Pfade As List(Of String))
    15. 'Hier die internen „private“ Variablen gehen setzen und nicht die Properties
    16. _Bilder = uebergebeneBilder
    17. _PfadederBilder = Pfade
    18. End Sub
    19. End Class
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @Bartosz Eine ReadOnly-Variable kannst Du im Konstruktor der Klasse mit einem Wert belegen.
    Wenn Du eine ReadOnly-Property erstellst, legt Dir die IDE bereits den Getter-Konstrukt an, Du must ihn nur ausfüllen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades Mit meinem Post #17 wollte ich ausdrücken:
    • Im Code in Post #6 , Button2_Click, weise ich der Liste direkt etwas zu. Das würde aber dann nicht gehen, wenn die List ReadOnly wäre. Logisch.
    • Unabhängig davon warnt mich "natürlich" der FxCopAnalyzer, man soll [generell] Listen ReadOnly setzen
    Mir ist bewusst, dass Listen ReadOnly sein sollten und dass man eigentlich keine Variablen, die Public sind, haben sollte.
    Meine Frage ist, ob man es gelöst bekommt. Dass ich weiterhin den Lists direkt etwas zuweise (auch wenn man es nicht sollte, aber wie gesagt 2000 Zeilen-Projekt will ich nicht zerstören...) und trotzdem der FxCopAnalyzer zufrieden ist. Das habe ich mit dem Code aus Post #15 geschafft. Auch wenn mir das CType(Value, List(Of String)
    etwas komisch erscheint.

    Ich weiß, wir haben hier einen Widerspruch. Sagt ihr nun
    [ ] das geht nicht
    [ ] Schalt den FxCopanalyzer aus
    [ ] das geht so und so

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()