.Contains gibt falschen Wert zurück?

  • VB.NET
  • .NET (FX) 4.0

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    .Contains gibt falschen Wert zurück?

    Hi zusammen.

    Ich hab grad ein Problem mit .Contains
    Eigentlich muss hier True zurückkommen, denn das Element ist definitiv vorhanden, wird aber False ausgegeben..
    Ein Bug?

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Mach an dieser Stelle mal:

    VB.NET-Quellcode

    1. If Not standortList.Contains(itm) Then
    2. If itm Is standort(1) Then Throw New ApplicationException("Contains funktioniert hier wirklich nicht.")
    3. MessageBox.Show("Contains funktioniert. Die Einträge sind inhaltlich gleich, aber nicht dieselben.")
    4. End If
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    In diesem Fall wird geprüft ob die Liste genau diese (nicht irgendeine mit identischen Werten) Instanz dieser Klasse beinhaltet. Ist es eine andere Instanz, so gibt dir dir Funktion richtigerweise false zurück.
    "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 @ISliceUrPanties
    danke, es lag an den verschiedenen Instanzen.
    Hab meine Klasse nu' wie folgt gebaut, jetzt läufts :thumbsup: - da muss man ja erstma drauf kommen

    VB.NET-Quellcode

    1. Public Class StandortSelection
    2. Implements IEquatable(Of StandortSelection) 'notwendig, damit diverse Instanzen miteinander verglichen werden können
    3. Property rwStandort As StandortRow
    4. Property GesellschaftAndStandortName As String
    5. Public Overloads Function Equals(ByVal other As StandortSelection) As Boolean Implements IEquatable(Of StandortSelection).Equals
    6. Return other.rwStandort Is Me.rwStandort AndAlso other.GesellschaftAndStandortName = Me.GesellschaftAndStandortName
    7. End Function
    8. End Class
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    poste mal die Klasse StandortSelection (wenns ühaupt eine Klasse ist).

    Wahrscheinlich kannste IEquatable<T> auch vermeiden - das zieht nämlich einen Rattenschwanz an weiteren zu implementierenden Interfaces nach sich.
    Etwa durch geeignete Verwendung von Linq-.Any(Selector) - Extension.

    Evtl. ist der Fehler auch, dass du unzulässigerweise mehrere StandortSelection-Objekte erzeugst.
    Dann wäre wohl besser das zu fixen, statt anderer Workarounds.

    Edit: Ah, du bist jetzt auf IEquatable.
    So, wie du's gemacht hast, wird das Fehlverhalten erzeugen, wenn du diese Klasse mal in einem Dictionary als Key verwendest.
    Und was mit Linq passiert ist auch unvorhersehbar, viele Linq-Extensions arbeiten intern mit Dictionaries/Hashsets.

    Diese Property GesellschaftAndStandortName - wäre da nicht besser, die würde ihren Wert direkt aus der enthaltenen StandortRow berechnen, oder geht das nicht?
    Auch glaube ich, es täte reichen, nur GesellschaftAndStandortName zum Vergleich heranzuziehen.

    Und, wie gesagt: prüfe auch, ob der Fehler nicht darin liegt, dass da mehrere Instanzen erstellt werden, wo man besser nur eine einzige wiederverwenden sollte.

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

    other.rwStandort Is Me.rwStandort prüft auch ob es sich um die gleiche Instanz handelt und nicht ob die Werte an sich identisch sind. Also eigentlich nicht das was du willst. Deine Prüfung klappt (in diesem Fall) nur weil zusätzlich GesellschaftAndStandortName verglichen wird, was vermutlich ein String ist.
    "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
    @ErfinderDesRades:
    Die Klasse hatte ich ja oben gepostet.
    Folgende "Problemstellung":

    Auf einer Form deklariere ich Private _standorte As New List(Of StandortSelection)
    Dann mit _standorte = StandortSelect(_appMod, _standorte) weiter.

    Dann will ich über eine CheckedListBox mir Daten der Standorte anzeigen lassen. -> rwStandort.GesellschaftRow.Name | rwStandort.Name
    Mein Problem ist der DisplayMember Zeile16 - deshalb hab ich mir die beiden Strings da zusammengehäkelt. Wenn ihr eine stilvollere Lösung habt, dann gerne.
    Ich brauch die Anzeige Gesellschaft | Name und die Selektion der CheckedListBox muss die jeweilige rwStandort ergeben.

    VB.NET-Quellcode

    1. ''' <summary> Zeigt eine CheckedListBox mit allen Standorten anhand UserRechten an und Returnt eine Liste mit Standort-Strings </summary>
    2. Public Function StandortSelect(appMod As String, standortList As List(Of StandortSelection)) As List(Of StandortSelection)
    3. Dim AllStandort As New List(Of StandortSelection)
    4. Dim SelectedStandort As New List(Of StandortSelection)
    5. Dim gesellschaften = GetGesellschaft(appMod)
    6. If gesellschaften Is Nothing Then Return Nothing
    7. For Each rwGesellschaft In gesellschaften
    8. Dim standorte = GetStandort(appMod, rwGesellschaft)
    9. For Each rwStandort In standorte
    10. AllStandort.Add(New StandortSelection With {.rwStandort = rwStandort, .GesellschaftAndStandortName = $"{rwStandort.GesellschaftRow.Name} | {rwStandort.Name}"})
    11. Next
    12. Next
    13. Using dlg As New dlgChkLb
    14. dlg.Text = "Standort(e) auswählen"
    15. dlg.chkLb.DataSource = AllStandort
    16. dlg.chkLb.DisplayMember = "GesellschaftAndStandortName"
    17. dlg.chkLb.ValueMember = "rwStandort"
    18. For i = 0 To dlg.chkLb.Items.Count - 1
    19. Dim itm = DirectCast(dlg.chkLb.Items(i), StandortSelection)
    20. If standortList Is Nothing OrElse standortList.Count = 0 Then 'Wenn noch keine Selektion vorhanden, dann alle markieren
    21. dlg.chkLb.SetItemChecked(i, True)
    22. Else 'vorherige Selektion wiederherstellen
    23. If standortList.Contains(itm) Then dlg.chkLb.SetItemChecked(i, True)
    24. End If
    25. Next
    26. If dlg.ShowDialog() <> DialogResult.OK Then Return Nothing
    27. For Each itm In dlg.chkLb.CheckedItems
    28. SelectedStandort.Add(DirectCast(itm, StandortSelection))
    29. Next
    30. End Using
    31. If SelectedStandort.Count = 0 Then Return Nothing
    32. Return SelectedStandort
    33. End Function


    Hier nochmal die Klasse:

    VB.NET-Quellcode

    1. Public Class StandortSelection
    2. Implements IEquatable(Of StandortSelection) 'notwendig, damit diverse Instanzen miteinander verglichen werden können
    3. Property rwStandort As StandortRow
    4. Property GesellschaftAndStandortName As String
    5. Public Overloads Function Equals(ByVal other As StandortSelection) As Boolean Implements IEquatable(Of StandortSelection).Equals
    6. Return other.rwStandort Is Me.rwStandort AndAlso other.GesellschaftAndStandortName = Me.GesellschaftAndStandortName
    7. End Function
    8. End Class


    @mrMo: nicht ganz, die StandortRow (rwStandort) bleibt ja die selbe, unabhängig von der Instanz
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „tragl“ ()

    ich könnt mir vorstellen, die ganze Klasse StandortSelection kann weg.
    Du kannst an der Klasse StandortRow eine Readonly Property GesellschaftAndStandortName dranprogrammieren - dann kannste gleich mit StandortRow arbeiten, und dann geht das mit .Contains() auch wieder so wie du ursprünglich dachtetest.
    Ich leg da ja immer einen Dataset-Ordner an, und für Erweiterungen dann Erweiterungs-Dateien, meist mit mehreren Erweiterungs-Klassen drin, weil das meist nicht so viel Code ist - je Klasse.

    Also deine Datei dtsLogistikTool.Logic.vb könnte (neben dem, was eh schon drin ist) noch sowas enthalten:

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Partial Class StandortRow
    3. Public ReadOnly Property GesellschaftAndStandortName As String
    4. Get
    5. Return $"{Me.GesellschaftRow.Name} | {Me.Name}"
    6. End Get
    7. End Property
    8. End Class
    9. End Class

    Aber eiglich dachte ich, du kenntest das schon, weil in meiner Version deines Werks finde ich bereits diese beiden Partial-Erweiterungen vor:

    VB.NET-Quellcode

    1. Partial Class dtsLogistik
    2. Partial Class TreeDataTable
    3. Private Sub TreeDataTable_ColumnChanged(sender As Object, e As DataColumnChangeEventArgs) Handles Me.ColumnChanged
    4. If e.Column IsNot NrColumn Then Return
    5. Dim rw = DirectCast(e.Row, TreeRow)
    6. rw.SortKey = GetTocSortKey(rw.Nr)
    7. End Sub
    8. End Class 'TreeDataTable
    9. Partial Class TreeRow
    10. Public Overrides Function ToString() As String ' Debugging-Hilfe: Im Haltemodus zeigt der Debugger nun die signifikante Eigenschaft der TreeRow
    11. Return Nr
    12. End Function
    13. End Class 'TreeRow
    14. End Class
    Ist ja dasselbe Prinzip.
    Oder war ich das selber, der das drangebastelt hat?
    Nee, aber ist glaub schon sehr lange her, dass wir das verzapft haben.

    Jedenfalls das Prinzip heisst: "Erweiterung generierten Codes mittels Partialer Klasse" - und ist was ganz anderes als die Erweiterungen, die man mittels Extension-Methods bewerkstelligt.
    Vielleicht das Schlüsselwort Partial recherchieren - (ist eiglich simpel: Man kann den Code einer Klasse auf mehrere Dateien aufteilen.)

    ErfinderDesRades schrieb:

    Ist ja dasselbe Prinzip.

    jo, macht absolut Sinn - bin ich mal wieder nicht drauf gekommen :S
    Teste ich am Wochenende mal -wird bestimmt klappen, wie immer :thumbsup:
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    ErfinderDesRades schrieb:

    könnte (neben dem, was eh schon drin ist) noch sowas enthalten:

    Hi, könnte ich mit sowas auch die Expressioned-Columns aus dem Designer "ersetzen"? also quasi die hinzugefügte Property auch im DGV als Column nutzen?

    Ansich mag ich die Expressioned-Columns schon, ist aber halt bescheiden wenn die vom Desginer zurückgesetzt werden wenn man da große Änderungen macht. Codeseitig wär' mir sowas lieber und am sinnvollsten
    dann eben in der Businesslogik
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    ErfinderDesRades schrieb:

    Nein - da gibts ein Fehl-Design beim Databinding

    Schade.. hätt' ja klappen können :P

    Aber:
    Angenommen ich lass die expression-Cols weg und nutze trotzdem die Property. Wäre es dann weniger Performant manuell eine Col einem DGV hinzuzufügen und über z.B.
    das RowPrepaint-Event die Property in dieser Col anzuzeigen? Also wäre eine direkte expression (kommt mit einem rutsch über die Bindingsource an's DGV) schneller als der von mir
    angedachte weg?
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Weiss ich nicht.
    Expressions machen iwas geheimnisvolles, aber jeder typProperty-Abruf macht ja auch was komisches.

    Daher wäre das vielleicht mal wert, ein paar Benchmarks damit laufen zu lassen.

    Generell ist das mit manuelle Properties bischen anständiger, weil der Compiler sichert die Syntax.
    Expressions sind ja im Ursprung beliebige Text-Werte (die evtl. kompiliert werden, vlt. auch nicht, vlt. werden Ergebnisse gecachet,...) - jedenfalls bei bestimmten Änderungen sind DataExpressions für Überraschungen gut - weisste ja.