Create a "clone" of this object, not point to it - vb.net

Let's say I got a list called
myFirstList
And then I want to create a copy of that list so I can do some tweaks of my own. So I do this:
mySecondList = myFirstList
mySecondList.doTweaks
But I noticed that the tweaks also affect the myFirstList object! I only want the tweaks to affect the second one...
And afterwards I will want to completely delete mySecondList, so I do mySecondList = Nothing and I'm good, right?

Adam Rackis, I don't like your "Of course it does", because it is not at all obvious.
If you have a string variable that you assign to another string variabe, you do not change them both when making changes to one of them. They do not point to the same physical piece of memory, so why is it obvious that classes do?
Also, the thing is not even consistent. In the following case, you will have all elements in the array pointing at the same object (they all end up with the variable Number set to 10:
SourceObject = New SomeClass
For i = 1 To 10
SourceObject.Number = i
ObjectArray.Add = SourceObject
Next i
BUT, the following will give you 10 different instances:
For i = 1 To 10
SourceObject = New SomeClass
SourceObject.Number = i
ObjectArray.Add = SourceObject
Next i
Apparently the scope of the object makes a difference, so it is not at all obvious what happens.

Here is how you do it:
'copy one object to another via reflection properties
For Each p As System.Reflection.PropertyInfo In originalobject.GetType().GetProperties()
If p.CanRead Then
clone.GetType().GetProperty(p.Name).SetValue(clone, p.GetValue(OriginalObject, Nothing))
End If
Next
in some cases when the clone object got read-only properties you need to check that first.
For Each p As System.Reflection.PropertyInfo In originalobject.GetType().GetProperties()
If p.CanRead AndAlso clone.GetType().GetProperty(p.Name).CanWrite Then
clone.GetType().GetProperty(p.Name).SetValue(clone, p.GetValue(OriginalObject, Nothing))
End If
Next

Since you have not divulged the type of item that you are storing n your list, I assume it's something that's implementing IClonable (Otherwise, if you can, implement IClonable, or figure out a way to clone individual item in the list).
Try something like this
mySecondList = myFirstList.[Select](Function(i) i.Clone()).ToList()

But I noticed that the tweaks also
affect the myFirstList object! I only
want the tweaks to affect the second
one...
Of course it does. Both variables are pointing to the same object in memory. Anything you do to the one, happens to the other.
You're going to need to do either a deep clone, or a shallow one, depending on your requirements. This article should give you a better idea what you need to do

Expanding on Adam Rackies' answer I was able to implement the following code using VB.NET.
My goal was to copy a list of objects that served mainly as data transfer objects (i.e. database data). The first the class dtoNamedClass is defined and ShallowCopy method is added. A new variable named dtoNamedClassCloneVar is created and a LINQ select query is used to copy the object variable dtoNamedClassVar.
I was able to make changes to dtoNamedClassCloneVar without affecting dtoNamedClassVar.
Public Class dtoNamedClass
... Custom dto Property Definitions
Public Function ShallowCopy() As dtoNamedClass
Return DirectCast(Me.MemberwiseClone(), dtoNamedClass)
End Function
End Class
Dim dtoNamedClassVar As List(Of dtoNamedClass) = {get your database data}
Dim dtoNamedClassCloneVar =
(From d In Me.dtoNamedClass
Where {add clause if necessary}
Select d.ShallowCopy()).ToList

Here's an additional approach that some may prefer since System.Reflection can be slow.
You'll need to add the Newtonsoft.Json NuGet package to your solution, then:
Imports Newtonsoft.Json
And given a class type of MyClass, cloning can be as easy as:
Dim original as New MyClass
'populate properties of original...
Dim copy as New MyClass
copy = JsonConvert.DeserializeObject(Of MyClass)(JsonConvert.SerializeObject(original))
So the approach is to first use the JSON converter to serialize the original object, and than take that serialized data and deserialize it - specifying the class type - into the class instance copy.
The JSON converters are extremely powerful and flexible; you can do all sorts of custom property mappings and manipulations if you need something the basic approach above doesn't seem to address.

this works for me:
mySecondList = myFirstList.ToList

clone is the object you are attempting to clone to.
dim clone as new YourObjectType
You declare it like that.

Related

Understanding Array.ConvertAll, can I DirectCast?

I have a base class, DtaRow, that has an internal array of Strings containing data. I have dozens of subclasses of DtaRow, like UnitRow and AccountRow, who's only purpose is to provide Properties to retrieve the values, so you can do aUnit.Name instead of aUnit.pFields(3).
I also have a DtaTable object that contains a Friend pRows As New Dictionary(Of Integer, DtaRow). I don't generally insert DtaRows into the DtaTable, I insert the subclasses like UnitRows and AccountRows. Any given table has only one type in it.
Over in the main part of the app I have an accessor:
Public Readonly Property Units() As IEnumerable
Get
Return Tables(5).pRows.Values 'oh oh oh oh table 5, table 5...
End Get
End Property
This, obviously, returns a list of DtaRows, not UnitRows, which means I can't do MyDB.Units(5).Name, which is the ultimate goal.
The obvious solution is to Dim ret As New UnitRow() and DirectCast everything into it, but then I'm building thousands of new arrays all the time. Uggg. Alternately I could put DirectCast everywhere I pull out a value, also uggg.
I see there is a method called Array.ConvertAll that looks like it might be what I want. But maybe that just does the loop for me and doesn't really save anything? And if this is what I want, I don't really understand how to use DirectCast in it.
Hopefully I'm just missing some other bit of API that does what I want, but failing that, what's the best solution here? I suspect I need...
to make a widening conversion in each DtaRow subclass?
or something in DtaTable that does the same?
You can use ConvertAll to convert an array into a different type.
Dim arr(2) As A
Dim arr2() As B
arr(0) = New B
arr(1) = New B
arr(2) = New B
arr2 = Array.ConvertAll(arr, Function(o) DirectCast(o, B))
Class A
End Class
Class B
Inherits A
End Class
In your case, I think it would look like this
Return Array.ConvertAll(Tables(5).pRows.Values, Function(o) DirectCast(o, UnitRow))
Note that this will create a new array each time.
You can cast the objects into a list(Of String) based on the field you want.
Return Tables(5).pRows.Values.Cast(Of DtaRow).Select(Function(r) r.name).ToList
YES! I went non-linear. This only works because of OOP...
My ultimate goal was to return objects from the collection as a particular type, because I knew I put that type in there in the first place. Sure, I could get the value out of the collection and CType it, but that's fugly - although in C# I would have been perfectly happy because the syntax is nicer.
So wait... the method that retrieves the row from the collection is in the collection class, not the various subclasses of DtaRow. So here is what I did...
Public ReadOnly Property Units() As IEnumerable
Get
Return Tables(dbTblUnits).pRow.Values
End Get
End Property
Public ReadOnly Property Units(ByVal K as Integer) As UnitRow
Get
Return DirectCast(Tables(dbTblUnits)(K), UnitRow)
End Get
End Property
Public ReadOnly Property Units(ByVal K as String) As UnitRow
Get
Return DirectCast(Tables(dbTblUnits).Rows(K), UnitRow)
End Get
End Property
Why does this solve the problem? Well normally if one does...
Dim U as UnitRow = MyDB.Units(K)
It would call the first method (which is all I had originally) which would return the .Values from the Dictionary, and then the Default Property would be called to return .Item(K). But because of the way the method dispatcher works, if I provide a more specific version that more closely matches the parameters, it will call that. So I provide overrides that are peers to the subclasses that do the cast.
Now this isn't perfect, because if I just call Units to get the entire list, when I pull rows out of it I'll still have to cast them. But people expect that, so this is perfectly acceptable in this case. Better yet, when I open this DLL in VBA, only the first of these methods is visible, which returns the entire collection, which means that Units(k) will call the Default Property on the DtaTable, returning a DtaRow, but that's fine in VBA.
OOP to the rescue!

Parameter.GetType() - Does the type has to be known at compilation time?

is something like this possible - and if so how?
Public Sub CreateGenericList(ByVal SampleObject As Object)
Dim genericList as new List(Of SampleObject.GetType())
End Function
I want to create a class that is able to deserialize a given XML-file.
The XML-file contains serialized values of a custom type, which is unknown at compilation time.
I thought it might be possible to just initialize the class with a parameter SampleObject and to then get that SampleObject's type for all further progressing.
But it seems as if the type for all operations has to be known at compilation time?
Is there a way around it or can you explain the problem to me?
The code example above is just to illustrate my problem
Thanks for the help,
Janis
Edit: Your answers might allready have solved the problem, I will read more on the topics "reflection" and "generics" and keep you up to date if i make any progress. So thanks allot for the help.
For those still interested:
I was asked for the purpose of my question and will try to explain it as best i can.
Public Function ReadAllObjects() As List(Of myObjectType)
Dim result As New List(Of myObjectType)
Dim ObjectSerializer As New System.Xml.Serialization.XmlSerializer(result.GetType)
Dim FileReader As New System.IO.FileStream(My.Settings.XMLPath, System.IO.FileMode.Open)
result = TryCast(ObjectSerializer.Deserialize(FileReader), List(Of myObjectType))
FileReader.Close()
RaiseEvent ReadingFinished()
Return result
End Function
This pretty much sums up what I want to create: A EasyXmlHandling.dll for further use, which will be initialized with the currently used variable type.
It is then supposed to be able to write and read from/to an XML-File in a really easy way, by just calling "ReadAllObjects" (returns a List of myObjectType) or "AddObject(ByVal theNewObject)"... (more functions)
I got all that to work with a custom class as type, so i could now easily re-use the EasyXmlHandling-code by just replacing that type in the sourcecode with whatever new class i will want to use.
I though would prefer to just call the .dll with a sample object (or the type of it) and to have it do everything else automaticly.
I hope that was understandable, but neither my english nor my technical vocabulary are really good ;)
So thanks again for the help and for reading through this.
I will try to get it to work with all your previous answers and will update the topic when i make further progress.
No, that is not possible (at least, not without using reflection). The whole point of specifying the type in a generic list, or any other generic type, is so that the compiler can perform compile-time type checking. If you aren't specifying the type at compile-time, there is no benefit to it at all. Beyond there being no benefit, it's also simply not supported. If you don't know the type at compile time, you should just use Object instead, since that will work with objects of any type, for instance:
Dim myList As New List(Of Object)()
If you need a list, however, which only allows one type of item, but that type is unknown at compile time, that is possible to do, but you would probably need to create your own non-generic list class for something like that. As far as I know, there is no non-generic list class provided in the framework which restricts its items to a single specified type.
Update
Now that you've explained your reason for doing this, it's clear that generics are your solution. For instance, you could implement it as as generic function, like this:
Public Function ReadAllObjects(Of T)() As List(Of T)
Dim result As New List(Of T)
Dim ObjectSerializer As New System.Xml.Serialization.XmlSerializer(result.GetType)
Dim FileReader As New System.IO.FileStream(My.Settings.XMLPath, System.IO.FileMode.Open)
result = TryCast(ObjectSerializer.Deserialize(FileReader), List(Of T))
FileReader.Close()
RaiseEvent ReadingFinished()
Return result
End Function
Then, you could call it, like this, passing it which ever type you want:
Dim cars As New List(Of Car) = ReadAllObjects(Of Car)()
Dim boats As New List(Of Boat) = ReadAllObjects(Of Boat)()
As you can see, that is the whole purpose of generics. They are a very powerful tool when you any to keep your code type-specific, but still be able to re-use it with different types. Reflection, on the other-hand is not a good fit in this particular situation. Reflection is also very useful, but should always be considered an option of last resort. If there is another way to do it, without reflection, that's usually the better way.

Structs in collections

I would like to store references to a bunch of structs in a collection. The general scaffolding looks like this:
Structure myStructType
Dim prop1 as String
Dim prop2 as int
End Structure
Dim myList as new List(Of myStructType)()
'Wrongness below
Dim myStruct as new myStructType()
myStruct.prop1 = "struct1"
myStruct.prop2 = 1
myList.Add(myStruct)
myStruct = new myStructType()
mystruct.prop1 = "number two"
mystruct.prop2 = 2
myList.Add(myStruct)
now this doesn't work, because it's referencing the same memory. What I would really want is the 'pass reference by value' behaviour that is also used for reference types, so that I can easily keep producing more of them.
Is there any way to fix this other than to make the structs into classes? Is this actually a proper way to use structs, or do I have it all wrong?
This code does the same thing whether it is a struct or a class because you are invoking new myStructType() for each object. That being said, be aware that later retrieving and modifiying those myStructType objects behave differently. If it is derrived froma structure then you are copying the data on a retrieve, leaving the original untouched in the list. If it is derrived from a class then you are getting a reference to that object and changes made using that reference change the instance in the list.
I still wonder what you are trying to accomplish (or avoid) by using structures instead of classes?

Newbie question: how do I create a class to hold data in Visual Basic Studio?

I'm really sorry. This must seem like an incredibly stupid question, but unless I ask I'll never figure it out. I'm trying to write a program to read in a csv file in Visual Basic (tried and gave up on C#) and I asked a friend of mine who is much better at programming than I am. He said I should create a class to hold the data that I read in.
The problem is, I've never created a class before, not in VB, Java, or anything. I know all the terms associated with classes, I understand at a high level how classes work no problem. But I suck at the actual details of making one.
So here's what I did:
Public Class TsvData
Property fullDataSet() As Array
Get
Return ?????
End Get
Set(ByVal value As Array)
End Set
End Property
End Class
I got as far as the question marks and I'm stuck.
The class is going to hold a lot of data, so I made it an array. That could be a bad move. I don't know. All i know is that it can't be a String and it certainly can't be an Integer or a Float.
As for the Getter and Setter, the reason I put the question marks in is because I want to return the whole array there. The class will eventually have other properties which are basically permutations of the same data, but this is the full set that I will use when I want to save it out or something. Now I want to return the whole Array, but typing "Return fullDataSet()" doesn't seem like a good idea. I mean, the name of the property is "fullDataSet()." It will just make some kind of loop. But there is no other data to return.
Should I Dim yet another array inside the property, which already is an array, and return that instead?
Instead of writing your own class, you could get yourself familiar with the pre-defined class System.Data.DataTable and then use that for holding CSV data.
In the last few years that I've been programming, I've never actually used a multi-dimensional array, and I'd advise you not to use them, either. There's usually ways of achieving the same with a better data structure. For example, consider creating a class (let's call it CsvRecord) that holds only one record; that is, only one line from the CSV file. Then use any of the standard collection types from the System.Collections.Generic namespace (e.g. List(Of CsvRecord)) to hold the entire data (ie. all lines) in the CSV file. This effectively reduces the problem to, "How do I read in one line of CSV data?"
If you want to take suggestion #2 even further, do as cHao says and don't simply lay out the information you've read as a CsvRecord; instead, create an object that reflects the actual content. For example, if your CSV file contains product–price information, call your CSV record class ProductInfo or something more fitting.
If, however, you want to go on with your current approach, you will need a backing field for the property, as demonstrated by Philipp's answer. Your property then becomes a "façade" that only delegates to this backing field. This is not absolutely necessary: You could simply make the backing field Public and let the user of your class access it directly, though that is not considered a good practice.
Ideally, you ought to have a class representing the specific data you want to read in. Setting an entire array at once is asking for trouble; some programs that read {C,T}SV files will freak out if all rows don't have the same number of columns, which is exceedingly easy to do if you can set the data to be an array of arbitrary length.
If you're trying to represent arbitrary data, frankly, you'd do just as well to use a List(Of String). If it's meant to be a table, you could instead read in the first line and make it a list as above (let's call it "headers"), and then make each row a Dictionary(Of String, String). (Let's call each row "row", and the collection (a list of these dictionary objects) "rows".) Just read in the line, split it like you did the first, and say something like row(headers(column number)) = value for each column, and then stuff it into 'rows'.
Or, you could use the data classes (System.Data.DataTable and System.Data.DataSet would do wonders here).
Usually you use a private member to store the actual data:
Public Class TsvData
Private _fullDataSet As String()
Public Property FullDataSet() As String()
Get
Return _fullDataSet
End Get
Set(ByVal value As String())
_fullDataSet = value
End Set
End Property
Note that this is an instance of bad design since it couples a concept to a concrete representation and allows the clients of the class to modify the internals without any error checking. Returning a ReadOnlyCollection or some dedicated container would be better.

.NET - Is there a way to programmatically fill all tables in a strongly-typed dataset?

I have a SQL Server database for which I have created a strongly-typed DataSet (using the DataSet Designer in Visual Studio 2008), so all the adapters and select commands and whatnot were created for me by the wizard.
It's a small database with largely static data, so I would like to pull the contents of this DB in its entirety into my application at startup, and then grab individual pieces of data as needed using LINQ. Rather than hard-code each adapter Fill call, I would like to see if there is a way to automate this (possibly via Reflection).
So, instead of:
Dim _ds As New dsTest
dsTestTableAdapters.Table1TableAdapter.Fill(_ds.Table1)
dsTestTableAdapters.Table2TableAdapter.Fill(_ds.Table2)
<etc etc etc>
I would prefer to do something like:
Dim _ds As New dsTest
For Each tableName As String In _ds.Tables
Dim adapter as Object = <routine to grab adapter associated with the table>
adapter.Fill(tableName)
Next
Is that even remotely doable? I have done a fair amount of searching, and I wouldn't think this would be an uncommon request, but I must be either asking the wrong question, or I'm just weird to want to do this.
I will admit that I usually prefer to use unbound controls and not go with strongly-typed datasets (I prefer to write SQL directly), but my company wants to go this route, so I'm researching it. I think the idea is that as tables are added, we can just refresh the DataSet using the Designer in Visual Studio and not have to make too many underlying DB code changes.
Any help at all would be most appreciated. Thanks in advance!
I saw all above solutions and they all are good, they inspired me to find my solution,
I made a more squeezed one, I know this is an old post, but I hope it helps people in the time to come,
Private Sub FillDataSet(ByRef ds As SvuDS)
For Each t As DataTable In ds.Tables
Dim adType As Type = Assembly.GetExecutingAssembly.GetType("ProjectNameSpace.MyDSTableAdapters." & t.TableName & "TableAdapter")
'Create Adapter Instance
Dim adapter As Object = Activator.CreateInstance(adType)
'Fill the Table
adapter.GetType().GetMethod("Fill").Invoke(adapter, New Object() {t})
Next
End Sub
I could've even inferred the namespace somehow too, but I wanted it to be simple, and it worked for me
There does not exists any api that lets you do this auto-fill of the entire typed-dataset or no such code is generated within typed-dataset that supports this. It is also difficult to do this because TableAdapters do not have a common base-class that can let you do this.
If you really need to do this, you'll have to maintain a collection of DataTable type-names and TableAdapter type-names and iterate over the collection to perform the dataset fill.
So I recommend to fill dataset for each table in 'hard-code' manner as your first code examples states.
EDIT
Here's one possible solution.
Define an Interface ITableAdapter as following
public interface ITableAdapter<TDataTable> : where TDataTable : DataTable
{
TDataTable SelectAll();
}
All TableAdapters are partial classes, so you can extend them and add your custom code in partial custom class for TableAdapter. Implement ITableAdapter on each TableAdapter in your typed-data-set. so it might look like this.
public partial class YourTableAdapter : ITableAdapter<YourDataSet.YourDataTableDataTable>
{
public YourDataSet.YourDataTableDataTable SelectAll()
{
return this.GetData();
}
}
Now, you can iterate over each type in your assembly and filter those of type ITableAdapter and call SelectAll() method on each of them fill it into your Dataset. :)
EDIT2
I just came up with another elegant solution for this problem. All you need to do is define the Interface ITableAdapter to map the already implemented methods in TableAdapters that are generated by the dataset-designer.
public interface ITableAdapter<TDataTable> : where TDataTable : DataTable
{
void Fill(TDataTable);
}
And extend your TableAdapter partial classes like this.
public partial class YourTableAdapter : ITableAdapter<YourDataSet.YourDataTableDataTable>
{
//No code required here, since Fill method is already defined in TableAdapter :)
}
OK, I think I have this worked out, and just want to share the results on the off chance that there are people out there who are as insane as I am.
Basically, all the magic happens using a couple of LINQ queries and reflection. For the purposes of this example, we will assume:
There is a strongly-typed DataSet created using the DataSet Designer in Visual Studio 2008, called dsTest. A module-level variable holds an instance of this DataSet and is called (appropriately enough), m_DataSet.
The tables themselves all follow a standard SQL Server naming convention, starting with "tbl".
As a part of this wizard, a series of table adapters were created for each table inside a namespace called dsTestTableAdapters.
Each adapter is named according to the table (so if we have "tblThingy", then an adapter named "tblThingyTableAdapter" would be created).
The application is in a namespace called, for lack of anything better, MyNamespace.
Here's the routine, called on Form Load:
Private Sub PopulateDataSet()
' Get our table adapters
Dim adapters As List(Of Type) = (From t As Type In System.Reflection.Assembly.GetExecutingAssembly.GetTypes Where t.Namespace = "MyNameSpace.dsTestTableAdapters" And t.Name.StartsWith("tbl") Select t).ToList
' Initialize our dataset
m_DataSet = New dsUtility
' Get our table names
Dim tableNames as List(Of String) = (From dtbl As DataTable In m_DataSet.Tables Select dtbl.TableName).ToList
' Loop through each table name and fill the table with the corresponding adapter
For Each iter As String In tableNames
' Grab the corresponding adapter name
Dim tableName As String = iter ' Grab a copy of the table name to avoid LINQ issues with iteration variables
Dim adapterType As Type = (From t As Type In adapters Where t.Name.StartsWith(tableName) Select t).First
' Given the adapter type name, use Reflection to create an instance
Dim adapter As Object = Activator.CreateInstance(adapterType)
' Use the instance to fill the appropriate table
adapter.Fill(m_DataSet.Tables(tableName))
Next
End Sub
I tried that, and it worked like a charm. Thanks, everyone, for your help and I hope you find this useful!
I think You have only one problem !
if this Typed dataset has relations between tables, this code won't load the datatables in the correct order !
Thanks, Mike, for the very thoughtful solution. Like you, I have been searching for a way to do what you've done, and to use the same mechanism to avoid an ugly switch statement (in C#) that has to case the generated TableAdapters to perform data binding updates.
I converted your VB code to C# as noted below. I made two changes (I'm using VS Express 2010 and .NET 4.0):
I changed the StartWith("tbl") method to EndsWith("TableAdapter") since a number of generated members in the TableAdapters namespace other than just the TableAdapters begin with "tbl" (assuming you want or need to follow that convention anyway), but only the TableAdapters end with "TableAdapter."
I changed the call to the Fill method since VS tells me at build time that the object referenced by "adapter" (which does look like a TableAdapter in the debugger) doesn't have a Fill method and there is no Fill extension method. I therefore cannot perform the Fill. I'm not at all sure why this didn't work. But in any case, I changed it to explicitly find the Fill method and then invoke that method. That seems to work.
Steve
public PopulateDataSet ()
{
// Get the TableAdapters
List<Type> tableAdapters = (from t in
System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
where t.Namespace == "MyNameSpace.m_DataSetTableAdapters"
&& t.Name.EndsWith("TableAdapter")
select t).ToList();
// Get the DataTable names
List<string> tableNames = (from DataTable dtbl in m_DataSet.Tables
select dtbl.TableName).ToList();
// Loop thru each table and fill it using the corresponding TableAdapter
foreach (string iter in tableNames)
{
string tableName = iter; // Stopt Linq issues with iteration vbls
Type adapterType = (from t in tableAdapters
where t.Name.StartsWith(tableName)
select t).First();
// Given the adapter type name, use Reflection to create an instance
Object adapter = Activator.CreateInstance(adapterType);
// Get a reference to the Fill method of the relevant adapter
MethodInfo method = adapter.GetType().GetMethod("Fill");
// Invoke the Fill method, passing in the relevant DataTable parameter
method.Invoke(adapter, new Object[] {m_DataSet.Tables[tableName]});
}
}
Some time ago I've found this thread and since then use this approach with success in my small project. But, recently I've found it out a bit limited. I have few queries for each table adapter in a data set with the names like "FillByContext", "FillById", "FillByName", etc., each one with a different set of parameters of different data types. All methods return tables with the same structure, but with different contents. So that I added some small "generalization" to the approach.
Private Sub MethodsAndParams(ds As DataSet,
dt As DataTable,
taParams() As Object,
taMethod As String)
Dim taType As Type = Assembly.GetExecutingAssembly.GetType(
"MyProjectName." +
ds.DataSetName +
"TableAdapters." +
dt.TableName +
"TableAdapter")
Dim ta As Object = Activator.CreateInstance(taType)
dt = ds.Tables(dt.TableName)
ta.GetType().GetMethod(taMethod).Invoke(
ta, New Object() {dt}.Union(taParams).ToArray)
End Sub
Now I can pass table adapter method names as strings and appropriate parameter sets as arrays of objects to this routine.