mehmast
asked on
vb.net parsing the CSV file - Collection was modified; enumeration operation may not execute
Hello Experts
I have a situation and wonder if someone can advice how to handle this.
In the example below I have 2 orders to process in the CSV file, I will loop through the total items using aCSV.OrderRequest.Items
and the first thing I do is to check if an order already exist, if it does then I reject the order and reduce the total number of items by 1, so the new values of
aCSV.OrderRequest.Items = 1, however the code intended to loop through for 2 times now when I have removed 1 item, its failing when it comes "Next" statement with an exception below
"Collection was modified; enumeration operation may not execute."
I have a situation and wonder if someone can advice how to handle this.
In the example below I have 2 orders to process in the CSV file, I will loop through the total items using aCSV.OrderRequest.Items
and the first thing I do is to check if an order already exist, if it does then I reject the order and reduce the total number of items by 1, so the new values of
aCSV.OrderRequest.Items = 1, however the code intended to loop through for 2 times now when I have removed 1 item, its failing when it comes "Next" statement with an exception below
"Collection was modified; enumeration operation may not execute."
Try
For Each aCSV As xCSV In _CSVs
For Each Item As cCSVProductItem In aCSV.OrderRequest.Items
NumOrders = Orders.IsRetailerOrderIdExist(Item.OrderItemNumber)
If (NumOrders.HasValue AndAlso NumOrders.Value > 0) Then
aCSV.RetailerOrderID = NumOrders.Value
'If the order id already exist - SEND THE CANCELLATION DISPATCH NOTFICATION
CreateCancelOrderNotification(GetOrderStatusFileName("REJECTED"), aCSV, Item)
aCSV.OrderRequest.RemoveItem(Item.OrderItemNumber)
Else
'To make sure the product is on the list,
If CheckIfProductExist(aCSV, Item) Then
'Capture the order and save in the database.
UpdateGiftDB(aCSV, Item)
End If
End If
Next
Next
Catch ex As Exception
Return False
End Try
ASKER
Hello Saige
Thank you so much for picking this up for me and for the example,
I am unable to do this though ?
For Each Item As cCSVProductItem In aCSV.OrderRequest.Items.As Enumerable ().Reverse ()
.....
Next
How can I adapt it in my code please?
Thank you so much for picking this up for me and for the example,
I am unable to do this though ?
For Each Item As cCSVProductItem In aCSV.OrderRequest.Items.As
.....
Next
How can I adapt it in my code please?
What compiler error do you receive?
-saige-
-saige-
An alternative approach would be to make a copy of your class, iterate through the copy and remove items from the original. You can then delete the copy.
You do this using the memberwiseclone property
copy=original.memberwisecl one
You do this using the memberwiseclone property
copy=original.memberwisecl
ASKER
Hi,
I cannot find AsEnumerable method in the list, and when I just used "Reverse" I get the following exception
Expression does not produce a value
I cannot find AsEnumerable method in the list, and when I just used "Reverse" I get the following exception
Expression does not produce a value
ASKER
Hello ChloesDad
Thanks for the suggestion. Sorry I did not understand what you meant by copying the class?
Please can you advice, below is my class
myclass.vb
---------------
Thanks for the suggestion. Sorry I did not understand what you meant by copying the class?
Please can you advice, below is my class
myclass.vb
---------------
Imports System
Imports System.Collections.Generic
Public Structure cCSVProductItem
Private _OrderItemNumber As String
Public Property OrderItemNumber() As String
Get
Return _OrderItemNumber
End Get
Set(ByVal value As String)
_OrderItemNumber = value
End Set
End Property
Private _Quantity As Double
Public Property Quantity() As Double
Get
Return _Quantity
End Get
Set(ByVal value As Double)
_Quantity = value
End Set
End Property
End Structure
Public Structure cCSVOrderRequest
Private _Items As List(Of cCSVProductItem)
Public Property Items() As List(Of cCSVProductItem)
Get
Return _Items
End Get
Set(ByVal value As List(Of cCSVProductItem))
_Items = value
End Set
End Property
Sub RemoveItem(ByVal Item As cCSVProductItem)
Me._Items.Remove(Item)
End Sub
Sub RemoveItem(ByVal OrderNumber As String)
For i As Integer = 0 To Me._Items.Count - 1
If Me._Items(i).OrderItemNumber = OrderNumber Then
Dim Item As cCSVProductItem
Item = Me._Items(i)
Me.RemoveItem(Item)
Exit For
End If
Next
End Sub
End Structure
Public Class xCSV
Private _CSVFileName As String = String.Empty
Public Property CSVFileName() As String
Get
Return _CSVFileName
End Get
Set(ByVal value As String)
_CSVFileName = value
End Set
End Property
Private _OrderRequest As cCSVOrderRequest
Public Property OrderRequest() As cCSVOrderRequest
Get
Return _OrderRequest
End Get
Set(ByVal value As cCSVOrderRequest)
_OrderRequest = value
End Set
End Property
Public Sub New()
'_OrderRequest.Items = New List(Of cCSVProductItem)
End Sub
End Class
Ensure that you have Imports System.Linq to the top of your codefile, then use:
aCSV.OrderRequest.Items.As Enumerable ().Reverse ()
-saige-
aCSV.OrderRequest.Items.As
-saige-
In your code, make the following changes
Dim copyOfOrder as ....... (whatever the class type acsv.orderrequest is)
Try
For Each aCSV As xCSV In _CSVs
CopyOfOrder = acsv.orderrequest.memberwiseclone
For Each Item As cCSVProductItem In copyoforder.Items
NumOrders = Orders.IsRetailerOrderIdExist(Item.OrderItemNumber)
If (NumOrders.HasValue AndAlso NumOrders.Value > 0) Then
aCSV.RetailerOrderID = NumOrders.Value
'If the order id already exist - SEND THE CANCELLATION DISPATCH NOTFICATION
CreateCancelOrderNotification(GetOrderStatusFileName("REJECTED"), aCSV, Item)
aCSV.OrderRequest.RemoveItem(Item.OrderItemNumber)
Else
'To make sure the product is on the list,
If CheckIfProductExist(aCSV, Item) Then
'Capture the order and save in the database.
UpdateGiftDB(aCSV, Item)
End If
End If
Next
Next
Catch ex As Exception
Return False
End Try
ASKER
Thanks Saige - I am still on 2.0 and not sure I can include linq dll in my project.
Thanks ChloesDad, I have amended the code as suggested below but is still giving me the same error
"Collection was modified; enumeration operation may not execute."
Please advice
Thanks ChloesDad, I have amended the code as suggested below but is still giving me the same error
"Collection was modified; enumeration operation may not execute."
Please advice
Dim TempOrderRequest As cCSVOrderRequest = New cCSVOrderRequest
Try
For Each aCSV As xCSV In _CSVs
' Private _CSVs As List(Of xCSV)
TempOrderRequest = aCSV.OrderRequest
For Each Item As cCSVProductItem In TempOrderRequest.Items
NumOrders = Orders.IsRetailerOrderIdExist(Item.OrderItemNumber)
If (NumOrders.HasValue AndAlso NumOrders.Value > 0) Then
aCSV.RetailerOrderID = NumOrders.Value
'If the order id already exist - SEND THE CANCELLATION DISPATCH NOTFICATION
CreateCancelOrderNotification(GetOrderStatusFileName("REJECTED"), aCSV, Item)
'Send email to Admin
CommonFunctions.SendErrorEmail("DUPLICATE")
UploadFilesToFtp(aCSV.CSVFileName)
aCSV.OrderRequest.RemoveItem(Item.OrderItemNumber)
Else
If CheckIfProductExist(aCSV, Item) Then
'Capture the order and save in the database.
UpdateGiftDB(aCSV, Item)
End If
End If
Next
Next
Which is why I posted the for with index version as well. That one does not require the System.Linq reference.
-saige-
-saige-
As a refresher:
Produces the following output -
-saige-
Module Module1
Sub Main()
Dim Items As New List(Of Integer) From {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
For i As Integer = Items.Count - 1 To 0 Step -1
If Items(i) Mod 2 = 0 Then
Items.RemoveAt(i)
End If
Next
Console.WriteLine("Standard For Loop with Index:")
For Each item As Integer In Items
Console.WriteLine(item)
Next
Console.ReadLine()
End Sub
End Module
Produces the following output -
-saige-
You did not copy my code.
My Line
CopyOfOrder = acsv.orderrequest.memberwi seclone
Your Line
TempOrderRequest = aCSV.OrderRequest
You missed off the MemberwiseClone, so you got another pointer to the same class, rather than a new instance of the class with the same values as the first.
My Line
CopyOfOrder = acsv.orderrequest.memberwi
Your Line
TempOrderRequest = aCSV.OrderRequest
You missed off the MemberwiseClone, so you got another pointer to the same class, rather than a new instance of the class with the same values as the first.
ASKER
Saige
Thanks again for the help - index method seems to have been working OK, only issue is that its processing last order first and so on ...
ChloesDad
I have tried using your line but then it was throwing the exception below..
Error 2 'Object.Protected Function MemberwiseClone() As Object' is not accessible in this context because it is 'Protected'.
I would like to make this method works but not sure what I am doing wrong.
Thank you so much both for your help!!! Really appreciate it.
Thanks again for the help - index method seems to have been working OK, only issue is that its processing last order first and so on ...
ChloesDad
I have tried using your line but then it was throwing the exception below..
Error 2 'Object.Protected Function MemberwiseClone() As Object' is not accessible in this context because it is 'Protected'.
I would like to make this method works but not sure what I am doing wrong.
Thank you so much both for your help!!! Really appreciate it.
Can you provide a sample xml file?
-saige-
-saige-
ASKER
Hi Saige
I am using CSV to process bulk orders, please see attached.
This is my revise code
I am using CSV to process bulk orders, please see attached.
This is my revise code
For Each aCSV As xCSV In _CSVs
For i As Integer = aCSV.OrderRequest.Items.Count - 1 To 0 Step -1
NumOrders = Orders.IsRetailerOrderIdExist(aCSV.OrderRequest.Items(i).OrderItemNumber)
If (NumOrders.HasValue AndAlso NumOrders.Value > 0) Then
aCSV.RetailerOrderID = NumOrders.Value
'If the order id already exist - SEND THE CANCELLATION DISPATCH NOTFICATION
CreateCancelOrderNotification(GetOrderStatusFileName("REJECTED"), aCSV, aCSV.OrderRequest.Items(i))
'Send email to Admin
CommonFunctions.SendErrorEmail(EmailOrderDetailsWhenException(aCSV, aCSV.OrderRequest.Items(i).OrderItemNumber))
'Upload the cancel/reject notification
UploadFilesToFtp(aCSV.CSVFileName)
' aCSV.OrderRequest.RemoveItem(aCSV.OrderRequest.Items(i).OrderItemNumber)
aCSV.OrderRequest.Items.Remove(aCSV.OrderRequest.Items(i))
Else
If CheckIfProductExist(aCSV, aCSV.OrderRequest.Items(i)) Then
'Capture the order and save in the database.
UpdateGiftDB(aCSV, aCSV.OrderRequest.Items(i))
Else
aCSV.OrderRequest.Items.Remove(aCSV.OrderRequest.Items(i))
End If
End If
Next
Next
TEST.csv
To implement Chloe's recommendation we need to change a few things. Here are the modified classes that should assist with this:
cCSVOrderRequest -
xCSV -
Now try this updated loop code to see if this works for you:
-saige-
cCSVOrderRequest -
Public Structure cCSVOrderRequest
Private _Items As List(Of cCSVProductItem)
Public Property Items() As List(Of cCSVProductItem)
Get
Return _Items
End Get
Set(ByVal value As List(Of cCSVProductItem))
_Items = value
End Set
End Property
Sub RemoveItem(ByVal Item As cCSVProductItem)
Me._Items.Remove(Item)
End Sub
Sub RemoveItem(ByVal OrderNumber As String)
For i As Integer = 0 To Me._Items.Count - 1
If Me._Items(i).OrderItemNumber = OrderNumber Then
Dim Item As cCSVProductItem
Item = Me._Items(i)
Me.RemoveItem(Item)
Exit For
End If
Next
End Sub
Public Shadows Function MemberwiseClone() As cCSVOrderRequest
Return Me.MemberwiseClone()
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not obj.GetType().Equals(Me.GetType()) Then
Return False
End If
Return Me = (DirectCast(obj, cCSVOrderRequest))
End Function
Public Overloads Function Equals(ByVal obj As cCSVOrderRequest) As Boolean
If Object.ReferenceEquals(obj, Nothing) Then
Return False
End If
Return Me = obj
End Function
Public Shared Operator =(ByVal lhs As cCSVOrderRequest, ByVal rhs As cCSVOrderRequest) As Boolean
If Object.ReferenceEquals(lhs, rhs) Then
Return True
End If
If Object.ReferenceEquals(lhs, Nothing) OrElse Object.ReferenceEquals(rhs, Nothing) Then
Return False
End If
Return If(Not lhs.Items Is Nothing AndAlso Not rhs.Items Is Nothing, lhs.Items.Equals(rhs.Items), False)
End Operator
Public Shared Operator <>(ByVal lhs As cCSVOrderRequest, ByVal rhs As cCSVOrderRequest) As Boolean
Return Not lhs = rhs
End Operator
End Structure
xCSV -
Public Class xCSV
Private _CSVFileName As String = String.Empty
Public Property CSVFileName() As String
Get
Return _CSVFileName
End Get
Set(ByVal value As String)
_CSVFileName = value
End Set
End Property
Private _OrderRequest As cCSVOrderRequest
Public Property OrderRequest() As cCSVOrderRequest
Get
Return _OrderRequest
End Get
Set(ByVal value As cCSVOrderRequest)
_OrderRequest = value
End Set
End Property
Public Sub New()
'_OrderRequest.Items = New List(Of cCSVProductItem)
End Sub
Public Shadows Function MemberwiseClone() As xCSV
Return Me.MemberwiseClone()
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not obj.GetType().Equals(Me.GetType()) Then
Return False
End If
Return Me = (DirectCast(obj, xCSV))
End Function
Public Overloads Function Equals(ByVal obj As xCSV) As Boolean
If Object.ReferenceEquals(obj, Nothing) Then
Return False
End If
Return Me = obj
End Function
Public Shared Operator =(ByVal lhs As xCSV, ByVal rhs As xCSV) As Boolean
If Object.ReferenceEquals(lhs, rhs) Then
Return True
End If
If Object.ReferenceEquals(lhs, Nothing) OrElse Object.ReferenceEquals(rhs, Nothing) Then
Return False
End If
Return If(Not lhs.CSVFileName Is Nothing AndAlso Not rhs.CSVFileName Is Nothing, lhs.CSVFileName.Equals(rhs.CSVFileName), False) AndAlso If(Not lhs.OrderRequest = Nothing AndAlso Not rhs.OrderRequest = Nothing, lhs.OrderRequest.Equals(rhs.OrderRequest), False)
End Operator
Public Shared Operator <>(ByVal lhs As xCSV, ByVal rhs As xCSV) As Boolean
Return Not lhs = rhs
End Operator
End Class
Now try this updated loop code to see if this works for you:
Try
For Each aCSV As xCSV In _CSVs
' Private _CSVs As List(Of xCSV)
TempOrderRequest = aCSV.OrderRequest.MemberwiseClone()
For Each Item As cCSVProductItem In TempOrderRequest.Items
NumOrders = Orders.IsRetailerOrderIdExist(Item.OrderItemNumber)
If (NumOrders.HasValue AndAlso NumOrders.Value > 0) Then
aCSV.RetailerOrderID = NumOrders.Value
'If the order id already exist - SEND THE CANCELLATION DISPATCH NOTFICATION
CreateCancelOrderNotification(GetOrderStatusFileName("REJECTED"), aCSV, Item)
'Send email to Admin
CommonFunctions.SendErrorEmail("DUPLICATE")
UploadFilesToFtp(aCSV.CSVFileName)
aCSV.OrderRequest.RemoveItem(Item.OrderItemNumber)
Else
If CheckIfProductExist(aCSV, Item) Then
'Capture the order and save in the database.
UpdateGiftDB(aCSV, Item)
Else
aCSV.OrderRequest.RemoveItem(Item.OrderItemNumber)
End If
End If
Next
Next
Catch ex As Exception
Console.WriteLine(String.Format("An exception occured: {0}", ex.Message))
End Try
-saige-
ASKER
thank you again Saige,
I will try this now, when I copy across your code, I am getting "Expression Expected" on this line
Return If(Not lhs.CSVFileName Is Nothing AndAlso Not rhs.CSVFileName Is Nothing, lhs.CSVFileName.Equals(rhs .CSVFileNa me), False) AndAlso If(Not lhs.OrderRequest = Nothing AndAlso Not rhs.OrderRequest = Nothing, lhs.OrderRequest.Equals(rh s.OrderReq uest), False)
May be I can use nested conditional statement for this?
Thank you
I will try this now, when I copy across your code, I am getting "Expression Expected" on this line
Return If(Not lhs.CSVFileName Is Nothing AndAlso Not rhs.CSVFileName Is Nothing, lhs.CSVFileName.Equals(rhs
May be I can use nested conditional statement for this?
Thank you
Yes this can be a nested conditional statment:
cCSVOrderRequest -
xCSV -
-saige-
cCSVOrderRequest -
Public Structure cCSVOrderRequest
Private _Items As List(Of cCSVProductItem)
Public Property Items() As List(Of cCSVProductItem)
Get
Return _Items
End Get
Set(ByVal value As List(Of cCSVProductItem))
_Items = value
End Set
End Property
Sub RemoveItem(ByVal Item As cCSVProductItem)
Me._Items.Remove(Item)
End Sub
Sub RemoveItem(ByVal OrderNumber As String)
For i As Integer = 0 To Me._Items.Count - 1
If Me._Items(i).OrderItemNumber = OrderNumber Then
Dim Item As cCSVProductItem
Item = Me._Items(i)
Me.RemoveItem(Item)
Exit For
End If
Next
End Sub
Public Shadows Function MemberwiseClone() As cCSVOrderRequest
Return Me.MemberwiseClone()
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not obj.GetType().Equals(Me.GetType()) Then
Return False
End If
Return Me = (DirectCast(obj, cCSVOrderRequest))
End Function
Public Overloads Function Equals(ByVal obj As cCSVOrderRequest) As Boolean
If Object.ReferenceEquals(obj, Nothing) Then
Return False
End If
Return Me = obj
End Function
Public Shared Operator =(ByVal lhs As cCSVOrderRequest, ByVal rhs As cCSVOrderRequest) As Boolean
If Object.ReferenceEquals(lhs, rhs) Then
Return True
End If
If Object.ReferenceEquals(lhs, Nothing) OrElse Object.ReferenceEquals(rhs, Nothing) Then
Return False
End If
Dim result As Boolean
If lhs.Items IsNot Nothing AndAlso rhs.Items IsNot Nothing Then
result = lhs.Items.Equals(rhs.Items)
Else
result = False
End If
Return result
End Operator
Public Shared Operator <>(ByVal lhs As cCSVOrderRequest, ByVal rhs As cCSVOrderRequest) As Boolean
Return Not lhs = rhs
End Operator
End Structure
xCSV -
Public Class xCSV
Private _CSVFileName As String = String.Empty
Public Property CSVFileName() As String
Get
Return _CSVFileName
End Get
Set(ByVal value As String)
_CSVFileName = value
End Set
End Property
Private _OrderRequest As cCSVOrderRequest
Public Property OrderRequest() As cCSVOrderRequest
Get
Return _OrderRequest
End Get
Set(ByVal value As cCSVOrderRequest)
_OrderRequest = value
End Set
End Property
Public Sub New()
'_OrderRequest.Items = New List(Of cCSVProductItem)
End Sub
Public Shadows Function MemberwiseClone() As xCSV
Return Me.MemberwiseClone()
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If obj Is Nothing OrElse Not obj.GetType().Equals(Me.GetType()) Then
Return False
End If
Return Me = (DirectCast(obj, xCSV))
End Function
Public Overloads Function Equals(ByVal obj As xCSV) As Boolean
If Object.ReferenceEquals(obj, Nothing) Then
Return False
End If
Return Me = obj
End Function
Public Shared Operator =(ByVal lhs As xCSV, ByVal rhs As xCSV) As Boolean
If Object.ReferenceEquals(lhs, rhs) Then
Return True
End If
If Object.ReferenceEquals(lhs, Nothing) OrElse Object.ReferenceEquals(rhs, Nothing) Then
Return False
End If
Dim result As Boolean = False
If Not lhs.CSVFileName Is Nothing AndAlso Not rhs.CSVFileName Is Nothing Then
If Not lhs.OrderRequest = Nothing AndAlso Not rhs.OrderRequest = Nothing Then
result = lhs.CSVFileName.Equals(rhs.CSVFileName) AndAlso lhs.OrderRequest.Equals(rhs.OrderRequest)
Else
result = False
End If
Else
result = False
End If
Return result
End Operator
Public Shared Operator <>(ByVal lhs As xCSV, ByVal rhs As xCSV) As Boolean
Return Not lhs = rhs
End Operator
End Class
-saige-
ASKER
Sure thanks again
I am now getting exception : System.StackOverflowExcept ion was unhandled
in the below below
Dim TempOrderRequest As cCSVOrderRequest = New cCSVOrderRequest
>> TempOrderRequest = aCSV.OrderRequest.Memberwi seClone()
-------------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- -
Public Shadows Function MemberwiseClone() As cCSVOrderRequest
Return Me.MemberwiseClone()
End Function
I am now getting exception : System.StackOverflowExcept
in the below below
Dim TempOrderRequest As cCSVOrderRequest = New cCSVOrderRequest
>> TempOrderRequest = aCSV.OrderRequest.Memberwi
--------------------------
Public Shadows Function MemberwiseClone() As cCSVOrderRequest
Return Me.MemberwiseClone()
End Function
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I would suggest that it_saige's final comment http#:a40450236 as the accepted solution as this gives the final code with my comment http#:a40448196 as an assisted solution as that provided the method required to solve the problem. a 50-50 share of points would seem reasonable.
ASKER
thanks for the help
Either:
Open in new window
Produces the following output:
-saige-