Unusual iLogic parameter (List of String) behavior

Unusual iLogic parameter (List of String) behavior

JBerns
Advisor Advisor
610 Views
4 Replies
Message 1 of 5

Unusual iLogic parameter (List of String) behavior

JBerns
Advisor
Advisor

Dear Community,

 

I was developing a DLL interface when I encountered an unusual behavior for parameters storing Lists of Strings.

 

The assembly contains four parts. Each part contains custom materials.

 

The DLL (Windows Form) would receive these lists and allow the user to select the material for each part.

 

Once the unusual behavior occurred, I simplified the program so as not to use the DLL.

 

The program would initially get a custom library materials and store them in a List of Strings named, oAsmLibMat_List. I modified it here to use InventorMaterialLibrary.

 

'Declare string lists
Dim oAsmLibMat_List, oLib_List1, oLib_List2, oLib_List3, oLib_List4 As New Generic.List(Of String)
'Declare asset library
Dim oAssetLib As AssetLibrary
'Declare asset
Dim oAsset As Asset
'Loop thru asset libs looking for NMC
For Each oAssetLib In ThisApplication.AssetLibraries
   'if NMC, get materials
   'If oAssetLib.DisplayName = "NMC Materials" Then
   If oAssetLib.DisplayName = "InventorMaterialLibrary" Then
      'Declare a material asset
      Dim material As MaterialAsset
      'Loop to get each material
      For Each material In oAssetLib.MaterialAssets
         'Add to string list
            oAsmLibMat_List.Add(material.DisplayName)
      Next
   End If
Next

' Display string list at top of program
MessageBox.Show("Top : oAsmLibMat_List =" & vblf & vbLf & String.Join(", ", oAsmLibMat_List.ToArray()), "DEBUG", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

 

For each of the four parts, I attempt to use a function to get the custom materials and then store respectively in List Strings named, oLib_List1, oLib_List2, etc.

 

oLib_List1 = GetPartDocMatls(oPartDoc, oAsmLibMat_List)
oLib_List2 = GetPartDocMatls(oPartDoc, oAsmLibMat_List)
oLib_List3 = GetPartDocMatls(oPartDoc, oAsmLibMat_List)
oLib_List4 = GetPartDocMatls(oPartDoc, oAsmLibMat_List)

I pass to the function the part document and the assembly material list. I use this so as not to add an existing assembly material to the part's list of custom materials.

 

Private Function GetPartDocMatls(LocPartDoc As PartDocument, MatList As Generic.List(Of String))
   Dim TempMatList As Generic.List(Of String) = MatList
   Dim oPartAsset As Asset
   For Each oPartAsset In LocPartDoc.MaterialAssets
      'Add material to list if it is not already in the list
      If Not TempMatList.Contains(oPartAsset.DisplayName) Then
         TempMatList.Add(oPartAsset.DisplayName)
      End If
   Next
Return TempMatList
End Function

I don't understand why the passed (oAsmLibMat_List) List of Strings is getting changed. I have tried with and without ByVal declarations.


At the end of the first function call, I expected only oLib_List1 to contain the assembly materials and the first part's custom materials.


However, the oAsmLibMat_List and oLib_List1 both contain the custom materials from part 1.


Because both lists change, the next call to the function to get custom materials from part 2, contains the custom materials from part 1.


This continues for parts 3 and 4.


At the end of the program, all the lists are identical. They contain the assembly materials and the custom materials from all four parts.

 

I thought I understood how functions, arguments, and returns behaved, but this has me confused.

 

I would welcome some insight and clarity.

 

Once I get this resolved, I can return to the task of building the DLL.

 

Thank you for your time and attention. I will attach the model once the forums are repaired.

See Rule_1 in the assembly.

 


Regards,
Jerry

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional
0 Likes
Accepted solutions (1)
611 Views
4 Replies
Replies (4)
Message 2 of 5

Michael.Navara
Advisor
Advisor
Accepted solution

This behavior is standard in .NET framework. You can't pass variable of type List(Of String) as value (independent copy of original list) but only as reference to original list.

See here for more information: https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/...

 

If you want to create four new lists, you need to clone original list to new one. See here: https://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c

 

Code sample

 

Sub Main

	Dim stringListOriginal As New List(Of String)
	stringListOriginal.Add("A")

	Dim newStringList = Clone(stringListOriginal)
	newStringList.Add("B")
	
	
	Logger.Info("stringListOriginal")
	Logger.Info(String.Join(vbCrLf, stringListOriginal))
	
	Logger.Info("newStringList")
	Logger.Info(String.Join(vbCrLf, newStringList))

End Sub

Public Function Clone(listToClone As List(Of String)) As List(Of String)
	Return listToClone.Select(Function(s)(s.Clone())).Cast(Of String).ToList()
End Function
Message 3 of 5

WCrihfield
Mentor
Mentor

There is a lot to absorb/process in my mind there, so just to clarify:

  • Are you wanting your source List (oAsmLibMat_List) to remain unchanged, while it is being referenced by the Function each time, then each of the 4 resulting Lists from the Parts should only contain the material DisplayName's of the materials found within the part of that loop?
  • Or do you want the source List (oAsmLibMat_List) to get all unique (not already included) material DisplayName's added to it, as it gets referenced by the Function each time, then each of the 4 resulting Lists still should only contain the names found within each part?

If you want the Function's returned List to only contain the material DisplayName's of the materials found in the specified Part, that are not already found in the supplied List, then create a New List (empty) within the Function to add the part's material names into, instead of loading it with the material named from the source list.  You can still check against the source list by its reference Variable, without putting them into your New List.  Then Return that New List as the result of the Function.

 

If you also want the source List to get updated will all the new unique material names from the parts, then perhaps you could do this as a secondary process, by combining the contents of the 4 resulting New Lists with the original source List's contents, outside of the Function.

https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.addrange?view=net-5.0#... 

https://stackoverflow.com/questions/2457609/whats-the-most-efficient-way-to-combine-two-listof-strin... 

https://stackoverflow.com/questions/9727415/merge-and-order-2-lists-of-different-objects-in-vb-net 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 4 of 5

JBerns
Advisor
Advisor

@Michael.Navara,

 

Thank you for the info, the links, AND the solution.

I implemented your solution and I now have four unique materials lists.

I may have spent a long time searching the VB forums for that solution. Thanks again for the assistance.

 

Regards,

Jerry

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional
0 Likes
Message 5 of 5

JBerns
Advisor
Advisor

@WCrihfield

 

Agreed, that was one of my longer support requests. I wish I could have attached the model to make the explanation easier.

 

My goal is to edit parts using a DLL interface. Changing the part sizes had been accomplished, so I moved on to materials. Here is an image of the Windows Form (DLL) and the parts in the assembly.

 

2021-08-11_9-31-20.png

 

I thought I should get the materials available at the assembly level and then get any custom materials from each part.

 

I wanted the custom materials only available to each respective part. In other words, Box1 should not have access to custom materials in Box2, Box3, or Box4.

 

I started with String Arrays, but VB forums suggested they were antiquated.

 

Therefore, I built the List of Strings for the assembly and then tried to build a unique list for each component. The lists were all changing despite my efforts to "clone" within the function. I did not realize that List(of T) objects always behaved as ByRefs instead of ByVal objects.

 

The goal is to get these unique lists to the DLL to populate comboboxes.

 

If there is a more practical way to get these unique lists to the DLL, I would welcome any advice.

(Still unable to attach documents to these posts as of this morning)

 

 

Regards,

Jerry

 

 

-----------------------------------------------------------------------------------------
CAD Administrator
Using AutoCAD & Inventor 2025
Autodesk Certified Instructor
Autodesk Inventor 2020 Certified Professional
Autodesk AutoCAD 2017 Certified Professional