6.5 Data Referencing in Invokes: DataTable, List & Dictionary Arguments
Key Takeaways
DataTable, List, Dictionary, and arrays are mutable reference types, so an In argument still lets the invoked code change their contents.
Assigning a new object to an In argument does not change the caller's variable; use Out or In/Out to return a new object.
Strings are immutable, so a changed string reaches the caller only through Out or In/Out.
Copy(),
New List(Of T)(source), and a new Dictionary built from the source protect the caller's data; the dictionary copy is shallow.An isolated Invoke Workflow File runs in a separate process and serializes arguments, so in-place changes are not visible to the caller.
6.5 Data Referencing in Invokes: DataTable, List & Dictionary Arguments
Core Concept: The exam description lists "Data referencing in invokes: Dt, List, Dictionary" as its own task. It tests one idea that surprises many developers: DataTable, List, and Dictionary are reference types. Passing one to Invoke Workflow File, Invoke Code, or Invoke Method passes a reference to the same object. So an argument marked In can still have its contents changed by the invoked code. What an In argument does prevent is replacing the caller's variable with a new object.
Value Types Versus Reference Types
| Type | Kind | Passed as In | Effect of changes inside the invoked code |
|---|---|---|---|
Int32, Double, Boolean, DateTime | Value type | A copy of the value | Invisible to the caller unless the argument is Out or In/Out |
String | Reference type, but immutable | A reference to text that cannot change | Any "change" creates a new string, so the caller sees it only through Out or In/Out |
DataTable, List(Of T), Dictionary(Of K, V), arrays | Mutable reference types | A reference to the caller's object | Adding rows, items, or keys and editing values are visible to the caller |
Three Scenarios to Know Cold
1. Mutating the object through an In argument
' Caller: dt_Invoices has 10 rows; invoke Enrich.xaml with in_dtInvoices (direction In)
' Inside Enrich.xaml:
in_dtInvoices.Rows.Add("INV-11", 250.0)
in_dtInvoices.Rows(0)("Status") = "Checked"
' Back in the caller: dt_Invoices now has 11 rows and row 0 shows Status = "Checked"
The same applies to List.Add, List.Remove, Dictionary(key) = value, and Dictionary.Remove. REFramework's in_Config dictionary is passed In to many workflows, so any workflow that writes to it changes the configuration for the rest of the job. That is why the template treats Config as read-only after Initialization.
2. Replacing the object through an In argument
' Inside the invoked workflow (in_dtInvoices is In):
in_dtInvoices = dt_Filtered ' points the local argument at a different table
' Back in the caller: dt_Invoices is unchanged
Assigning a new object only redirects the argument inside the invoked workflow. To hand a new table back, use an Out argument, such as out_dtFiltered, or In/Out (io_dtInvoices).
3. Protecting the caller's data
When the invoked workflow must experiment on a table without touching the original, pass or create a copy:
Dim dt_Work As DataTable = in_dtInvoices.Copy() ' schema + rows, independent object
Dim lst_Work As New List(Of String)(in_lstIds) ' new list with the same items
Dim dict_Work As New Dictionary(Of String, Object)(in_Config) ' shallow copy of the dictionary
A dictionary copy made this way is shallow: if a value is itself a reference type, such as a DataTable stored in the dictionary, both dictionaries still point to that same table.
Invoke Code and Invoke Method Follow the Same Rules
- Invoke Code: an argument with direction In of type
DataTablecan be modified in place withRows.Addor by editing cells, and the caller sees the change. Declare an Out or In/Out argument only when the code creates a new object that must be returned. - Invoke Method: calling an instance method on a
TargetObject, such aslst_Items.Sort()ordt_Report.Clear(), changes that object in place. There is no copy.
The Isolated Exception
Invoke Workflow File has an Isolated option that runs the invoked workflow in a separate robot process, for example to contain a crash-prone application. Across process boundaries, arguments are serialized and copied rather than shared:
| Invocation | How a DataTable In argument reaches the child | Are in-place changes visible to the caller? |
|---|---|---|
| Normal (not isolated) | Same object in the same process | Yes |
| Isolated | A serialized copy in another process | No; return results through Out or In/Out arguments |
Isolated invocations also require argument types that can be serialized. A live object such as a UI element handle or an open database connection cannot cross into the separate process.
Parallel Branches and Shared References
Because every branch of a Parallel or Parallel For Each activity sees the same objects, two branches that add rows to the same DataTable are writing to one object. A DataTable is safe for concurrent reads only, so give each branch its own table and merge the results afterwards.
Checklist for Reviews
- For every DataTable, List, or Dictionary argument, ask whether the invoked workflow is allowed to change it. If not, document it as read-only or pass a copy.
- Use Out or In/Out whenever the invoked workflow assigns a new object that the caller needs.
- Do not rely on in-place changes when the invocation is Isolated.
- Name arguments with their direction prefix (
in_,out_,io_) so readers can see the contract. UiPath's Workflow Analyzer includes naming rules for this. - Remember that strings never change in place;
in_Text.Trim()returns a new string.
A workflow invokes Enrich.xaml with dt_Invoices (10 rows) passed as an In argument. Enrich.xaml calls in_dtInvoices.Rows.Add once. The invocation is not isolated. How many rows does dt_Invoices have after the invoke returns?
10, because In arguments are always copies.
0, because the argument was cleared when the invoked workflow ended.
It depends on whether the workflow is VB.NET or C#.
11, because the DataTable is passed by reference and the row was added to the same object.
Inside an invoked workflow, the developer writes in_lstIds = New List(Of String) From {"A", "B"} for an argument with direction In. What does the caller's list contain afterwards?
Its original items, because assigning a new object to an In argument only changes the local reference.
Only "A" and "B", because lists are reference types.
Its original items plus "A" and "B".
Nothing; the assignment throws an InvalidOperationException.
Invoke Workflow File runs Transform.xaml with the Isolated option. Transform.xaml edits cells of an In DataTable argument. What does the caller see?
The edited cells, exactly as with a normal invoke.
An exception, because DataTables cannot be passed to isolated workflows.
The original values, because the isolated workflow runs in a separate process and receives a serialized copy; results must come back through Out or In/Out arguments.
Only the first edited row, because isolated workflows commit one change at a time.
Sections you finish are checked off in the contents.