You can use the class %ZEN.proxyObject, e.g.:

Class demo.Customer Extends %RegisteredObject
{

Property p1 As %String;

Property p2 As %String;

Property list As %Collection.ListOfDT;

/// d ##class(demo.Customer).Test()
ClassMethod Test()
{
  customer=##class(demo.Customer).%New()
  customer.p1="p1"
  customer.p2="p2"
  customer.list=##class(%ListOfDataTypes).%New()
  customer.list.InsertList($lb(1,"two",,"four"))
  
  appointment=##class(%ZEN.proxyObject).%New()
  appointment.a1="a1"
  appointment.a2="a2"
  appointment.list=##class(%ListOfDataTypes).%New()
  appointment.list.InsertList($lb(2,3,"test",8))
  
  ; Cancellation
  response=##class(%ZEN.proxyObject).%New()
  response.Code="Cancellation"
  response.Info="Info_Cancellation"
  response.Code,":",! response.%ToJSON(,"2aelow")
  
  response.%Clear()

  ; Customer
  response.Code="Customer"
  response.Info=customer
  
  !!,response.Code,":",! response.%ToJSON(,"2aelow")

  response.%Clear()

  ; Appointment
  response.Code="Appointment"
  response.Info=appointment
  
  !!,response.Code,":",! response.%ToJSON(,"2aelow")
}

}
USER>##class(demo.Customer).Test()
Cancellation:
{
  "Code":"Cancellation",
  "Info":"Info_Cancellation"
}
 
Customer:
{
  "Code":"Customer",
  "Info"{
    "p1":"p1",
    "p2":"p2",
    "list":["1","two","","four"]
  }
}
 
Appointment:
{
  "Code":"Appointment",
  "Info"{
    "a1":"a1",
    "a2":"a2",
    "list":[2,3,"test",8
    ]
  }
}

Initially the question was about alternative ways of solving the issue (in addition to recursive FileSet and $ZSEARCH).

I just proposed a third method, namely using the capabilities of the OS itself. Maybe someone here didn't know about it.

Which option at end to choose - to solve the developer.


We here vote for the best solution or in general for offered solutions?

If the first, then I'll pass.

Anything with this flag can change or be removed with no warning.

There are a few comments:

  • Let's say that the developers changed something in new versions of the DBMS. Is this a problem?

    It is enough to check Caché Recent Upgrade Checklists, where usually there is a ready list of changes that may affect existing user code, for example.

    Note that this can apply to absolutely any member of a class, and not even marked as [Internal]. Suffice it to recall the recent story with JSON support.

  • For a class does not exist flag [Internal], the warning is only on the level of comments.

    As for the other members of the class, according to the documentation this flag is for other purposes, namely:

    Internal class members are not displayed in the class documentation. This keyword is useful if you want users to see a class but not see all its members. proof
  • In any case, the final choice for developer.

Does this example need to handle this?

Correct, of course, to close the device:

#include %systemInclude

#dim cDev As %String $IO

; see "dir /?" and RunCommandViaZF()
##class(%Net.Remote.Utility).RunCommandViaCPIPE(...,.dev,.con)
/*
...
*/
c:($get(dev)'=""dev:"I"
cDev
Also, do you not worry that its an internal class?

No, since for me internal ≠ deprecated.

However, given the openness of the source code, you can make own similar method, thereby to protect yourself from possible issues in the future.

<...> but maybe there's a better solution?

Yes, of course.

E.g. (for Windows x64):

#include %systemInclude

; see "dir /?"
##class(%Net.Remote.Utility).RunCommandViaCPIPE($$$FormatText("dir /A-D /B /S %1",$$$quote("C:\Program Files (x86)\Common Files\InterSystems")),,.con)
; string -> array
##class(%ListOfDataTypes).BuildValueArray($lfs($e(con,1,*-2),$$$NL),.array)
zw array

Refine your version $zv. Perhaps in older versions there were bugs that were then fixed.

Simple test:

Class my.children Extends %Persistent
{

Property p1;

Relationship parent As my.parent [ Cardinality = parent, Inverse = children ];

Method %OnConstructClone(
  object As %RegisteredObject,
  deep As %Boolean = 0,
  ByRef cloned As %String) As %Status [ Private, ServerOnly = 1 ]
{
  i%p1 = object.p1 _ " cloned"
  $$$OK
}
}

Class my.parent Extends %Persistent
{

Property p1;

Relationship children As my.children [ Cardinality = children, Inverse = parent ];

ClassMethod Fill()
{
  ;d ##class(my.parent).Fill()
  
  ..%KillExtent()
  
  i = 1:1:3 {
    = ..%New()
    p.p1 = "parent["_i_"]"
    j = 1:1:2 {
      = ##class(my.children).%New()
      c.p1 = $$$FormatText("children[%1,%2]",i,j)
      p.children.Insert(c)
    }
    p.%Save()
  }
  zw ^my.parentD
  !,"_______",!!
  
  i = 1,3 ..%OpenId(i).%ConstructClone($$$YES).%Save()

  ; or so - the result is the same
  ; f i = 1,3 d ..%OpenId(i).%ConstructClone($$$NO).%Save()

  zw ^my.parentD
}

Method %OnConstructClone(
  object As %RegisteredObject,
  deep As %Boolean = 0,
  ByRef cloned As %String) As %Status [ Private, ServerOnly = 1 ]
{
  i%p1 = object.p1 _ " cloned"
  $$$OK
}
}


USER>$zv
Cache for Windows (x86-64) 2017.2 (Build 672U) Wed May 10 2017 20:43:42 EDT
USER>##class(my.parent).Fill()
^my.parentD=3
^my.parentD(1)=$lb("","parent[1]")
^my.parentD(1,"children",1)=$lb("","children[1,1]")
^my.parentD(1,"children",2)=$lb("","children[1,2]")
^my.parentD(2)=$lb("","parent[2]")
^my.parentD(2,"children",3)=$lb("","children[2,2]")
^my.parentD(2,"children",4)=$lb("","children[2,1]")
^my.parentD(3)=$lb("","parent[3]")
^my.parentD(3,"children",5)=$lb("","children[3,2]")
^my.parentD(3,"children",6)=$lb("","children[3,1]")
 
_______
 
^my.parentD=5
^my.parentD(1)=$lb("","parent[1]")
^my.parentD(1,"children",1)=$lb("","children[1,1]")
^my.parentD(1,"children",2)=$lb("","children[1,2]")
^my.parentD(2)=$lb("","parent[2]")
^my.parentD(2,"children",3)=$lb("","children[2,2]")
^my.parentD(2,"children",4)=$lb("","children[2,1]")
^my.parentD(3)=$lb("","parent[3]")
^my.parentD(3,"children",5)=$lb("","children[3,2]")
^my.parentD(3,"children",6)=$lb("","children[3,1]")
^my.parentD(4)=$lb("","parent[1] cloned")
^my.parentD(4,"children",7)=$lb("","children[1,2] cloned")
^my.parentD(4,"children",8)=$lb("","children[1,1] cloned")
^my.parentD(5)=$lb("","parent[3] cloned")
^my.parentD(5,"children",9)=$lb("","children[3,2] cloned")
^my.parentD(5,"children",10)=$lb("","children[3,1] cloned")