Dynamic Objects, E xpressions & S cripts in Dot-Net

Download DOES.NET (free)

Common technique.

    DOES.NET technology allows you writing and executing expressions and scripts in NET languages without compilation. CODEDOM assembly makes DOES.NET unuseful in NET Framework. But this technology can be really useful in Silverlight (in browser) where CODEDOM is absent. You can declare and use dynamic variables (objects) right in scripts without compilation. If you used dynamic languages earlier then you be glad receiving ability to use dynamic code, macro substitutions and other powers of simple interpreter in Silverlight.  DOES.NET is a minimal set of means to create any dynamic code (except type declarations).

    This part of documentation describes DOES.NET technology using without internal details.


    DOES.NET net components include two library for each NET platform:

    Include references to these dll into your project and add using DOES; using DOESExplWPF; into code.

    ! DOES.NET solutions were created for internal use in our projects. Let us know about your interests and problems and we'll try develop this technology and fix bugs.

"Does" object initialization.

    You should call Init method of Does class object to initialize it.  And you can change any default settings to optimize memory use before initialization ofDoes class object. These settings depend on how many dynamic objects and functions you plan to use in your scripts.

Does.PublicObjectsDefault    - initial length of table to store public objects. The default value is 5000;

Does.PrivateObjectsDefault    - initial length of table to store private objects. The default value is 5000. Table of private objects will be created for each level of stack when you call DOES.NET function;

Does.PublicFunctionsDefault    - initial length of table to store public functions. The default value is 1000;

Does.PrivateFunctionsDefault    - initial length of table to store private functions. The default value is 1000. Table of private functions will be created for each level of stack when you call DOES.NET function;

Does.MaxStackLevels   - initial length of stack. The default value is 1000;

    These are just initial values. DOES.NET uses these values to create tables. But if the length of any table is exceeded when DOES.NET try to create new object, then DOES.NET increases a size of table. But this operation takes additional time and memory.

   Your C# code looks like:

using System;
using ...;
using DOES;
namespace YourNameSpace
    public partial class YourAppClass

        Does oDoes;

        public YourAppClass()    // Constructor or other method before you begin to use DOES.NET
      oDoes = new Does();
            oDoes.PrivateFunctionsDefault = 100 ;    // optional
            oDoes .PrivateObjectsDefault = 300 ;   // optional

Error occurs if you don't call Init() method before Does class object use.

Simple example.

    Next example demonstrates few main DOES.NET abilities and has not any sense. You can see the technique when DOES.NET dynamic objects of any types can be declared, you can assign values to them before executing of DOES.NET scripts, and take values back from DOES.NET objects after script executed.

oDoes.Declare( "nVar1" , 10 );
oDoes.Declare( "nVar2" , 20 );
oDoes.Declare( "nVar3" );
    "Function Func1(Parm1,Parm2,Parm3);" +
        "nVar1=(Parm1+Parm2+Parm3)/33;" +
        "nVar1=Decimal.Round(nVar1,2);" +
        "Return nVar1+10,0;" +
    "EndFunc;" +
    "" +
    "nVar3=nVar1+nVar2;" +
    "nVar4=nVar3*nVar1/nVar2;" +
    "sVar1=nVar4.ToString();" +
    "i=0;" +
    "While i<1000 && nVar4>0,0;" +
        "i=i+1;" +
        "nVar4=nVar4-Func1(nVar1,nVar2,nVar3)-i;" +
        "?nVar4.ToString();" +
    "End;" +
    "If nVar4>0;?\">0\";" +
    "else; ?\"<=0\"; end;" );
Decimal v3 = (Decimal)oDoes.Get("nVar3" );
Decimal v2 = (Decimal)oDoes.Get("nVar2" );

    Inside script you can also: declare objects of any types; assign values; evaluate expressions with references to DOES.NET objects, NET types, members of objects and types; can create arrays and reference their elements in expressions; can use constructions IF-ELSE-END and WHILE-CONTINUE-BREAK-END loops; can declare and call functions, use macro substitutions, and etc...

    Note! Use comma or point in numeric constants to convert them to Decimal (0,00 or 0.0). Else constant will be converted to Int32.

Dynamic objects.

    Dynamic objects in DOES.NET can have one of three status: Public, Private, Local . And they can be declared and be accessible from NET language code or inside DOES.NET script. Object names are case insensitive.

Public objects.

    Public objects are objects declared in root (zero) stack level and can be accessible from any function in any level of stack.

Private objects.

    Private objects are objects declared in any stack level and can be accessible in current function and in functions called from current (in next levels of stack).

Local objects.

    Local objects are objects declared in any stack level and can be accessible only in current function.

Declaring in C# code.

    To declare DOES.NET objects in C# code use methods Declare and Set of Does class object.

        public bool Declare( String Name)   - this method declares object without value assignment.

        public bool Declare( String Name, Object Value)   - this overload of Declare method allows to declare object and to assign value of any type.

        public bool Set( String Name, Object Value)  - actually equals to Declare overload.

    If object with the same name already exists then two last methods just replace its value without exception creating. First method do nothing.


oDoes.Declare( "nVar2" , 20 );
oDoes.Declare( "nVar3" );
oDoes.Set( "nVar1" , 10 );

Declaring in DOES.NET script.

    If dynamic objects was declared in script (in root stack level) then they also can be visible after script executed and can be accessible from C# and VB# code.

Declaring empty objects.

    Use commands: Public, Create and Local to declare empty objects inside DOES.NET script. For example:

    "...; Public pVar1,pVar2,pVar3; Private rVar1,rVar2;" +
    "Local lVar1,lVar2,lVar3,lVar4; ...; ...;" + ...

    DOES.NET creates dynamic objects for each name listed after directive and delimited with comma.

Declaring objects of specified type

    Use function New(sType) to declare DOES.NET objects of specified type or to replace existing objects with new values of specified type.

            "...; Var10=New(\"System.String\"); Var10=\"This is string\";...;  Var11=String.Copy(Var10); ...;"

    You must pass valid type name as string as parameter into function New. And assembly should be accessible.

Declaring arrays.

Use function Array(sType,Dim1[,Dim2[,...,DimN]]) to create arrays of objects of specified type. For example:

"...; Arr1=Array(\"System.String\",10); ...;"     - this script fragment creates one-dimension array String[10];

"...; Arr2=Array(\"System.Windows.Controls.TextBloc\k",10,3,7); ...;"      - this script fragment creates three-dimension array TextBlock[10,3,7];

Refer to elements of arrays in script using square brackets:

"...; Arr1[3]=\"String[3]\";"+
" MyGrid.Children.Add(Arr2[7,2,5]);"

Visibility scope.

    Public objects can be accessible from anywhere. Private objects can be accessible in current function and functions called inside current. But if private object with the same name is created in nested function (sublevels of stack) , then public object and private objects of higher levels with the same names will be inaccessible from this function and functions called from this function. All local variables, declared in function, hide public variables with the same names and private variables with the same names declared in external functions (higher levels of stack), but only inside current function except nested functions.

Creation without declaration.

    You don't need declare private variables inside script using Private command. When you assign value to variable then DOES.NET creates new private object if object with this name doesn't exist.

"...; nVar1=10;nVar2=20;"+
"nVar3=nVar1+nVar2; ...;"


    DOES.NET clears all dynamic objects in all levels of stack except root (zero) after script execution ( oDoes.Execute(sScript) ; ). To decrease a quantity of  operations with memory and to increase a speed DOES.NET doesn't erase private objects, functions and their tables after each function call, because this operation takes a time. So. If some variables prevent you work then you should clear they manually:

    in script:

"...; Clear nVar1,nVar2,nVar3; Clear *Var1,nVar*,*Var*;"

    in code:


    Any way use * in beginning or end of mask or full object names.

Referencing from C# code.

    After script executed, you can refer to DOES.NET object of root stack level in C# or VB code using Get method of Does class object:

Decimal v3 = ( Decimal )oDoes.Get( "nVar3" );
String v10 = ( String)oDoes.Get("nVar10");
Decimal v2 = ( Decimal )oDoes.Get( "nVar2" );


    Expressions in DOES.NET can consist from references, DOES.NET functions , constants and operators.

    References can be to: DOES.NET objects; Types in available assemblies; members of objects; static members of types; elements of arrays.

    DOES.NET uses following order when identify each identifier found in expression:

    Operators can be:

    The priority of operators is:  (* / )  (+ -) (Comparison) (Logic)

    Example of expression:

        (nVar1+nVar2)*sVar1.Length > Func1(nVar3) || Func2(nVar4) == nVar5/123

    Script lines can include expressions. And you can evaluate expressions in DOES.NET explorer.

    Note! If expression is complex and consist of several actions - set a priority of operation explicitly using brackets ( ) ! For example:

        this expression will produce error:

            While Func1(nVar1,nVar2,nVar3)>1.0 && Func2(nVar1,nVar2,nVar3)>2.0 && Func3(nVar1,nVar2,nVar3)>3.0;

        take members of single operation in brackets!!!

            While (  Func1(nVar1,nVar2,nVar3)>1.0 && Func2(nVar1,nVar2,nVar3)>2.0  )  && Func3(nVar1,nVar2,nVar3)>3.0;


Using constants.

    DOES.NET expression syntax allows to use constants:


DOES.NET objects referencing.

    Simply use DOES.NET object names to operate their values in expressions. Object names are case insensitive.

Assemblies classes referencing.

    If a type has static members then you can call such static methods or refer to static fields and properties of this type. If you use type name without assembly specification then DOES.NET searches type in all available assemblies and only if dynamic object and functions with the same name aren't found before. But you can optimize this searching. Type names are case sensitive.

Members referencing.

    You can refer to members of dynamic object or static members of type with using of common syntax Object.Member.Member... (point as delimiter)


    and etc...  Member names are case sensitive.

DOES.NET functions referencing.

    Each name-identifier, found in expression, DOES.NET searches in objects tables first. Second - in functions tables. Order is from current stack level to root. The scope of visibility is the same to objects. The number of parameters can be less or equal to number of parameters declared for this function. Function names are case insensitive.


References optimization.

    In cases when you have declared a lot of dynamic objects and functions and have loaded a lot of assemblies, the search time can grow. Expression syntax allows you optimize references by pointing a way to search name-identifier. You can use next syntax:

~ prefix - specifies that this name is DOES.NET function and prevents searching in DOES.NET object tables.  ( ~Func1(nVar1) );

# prefix - specifies that this name is type, which should be found in assemblies, and prevents searching in dynamic objects and functions.  ( #String.Copy(\"sting\") )

^ delimiters to define a full type. If name includes ^ symbol then DOES.NET replaces these symbols with points and accepts the result as full name of type. In this case DOES.NET does not search type in all assemblies but try invoking member without checking of its existence. Make sure a full type is correct!  (  #System^String.Copy(\"sting\") )

    You can essentially increase a speed of script executing with using of this references optimization.

Unary operations

    Use Does class method static bool Not(Object _val) or static bool not(Object _val) to make unary inversion. It looks like "...; IF Does.Not(False); ...;"

Macro substitutions

    In general DOES.NET is a technology of macro substitutions for NET languages (C# and VB). But you can use nested evaluations inside scripts. In all cases you can evaluate just completed commands and can't substitute separated clauses (like in FoxPro). And any member of expressions (except operators) can be as string subexpression stored in variable.

    Eval(sExpression) function allows to use expression evaluations instead of macro substitutions in DOES.NET . For example:

"...; sMacro=\"nVar1+nVar2\";"+

    If you need to run a script inside another script then you can use Exec(sScript) function. For example:

"...; sMacro=\"nVar1=10;nVar2=20;\";"+


    Method Execute(sScript) allows script executing.  

Script lines.

     Script is a set of commands in one string. Each command should be ended with semicolon (;) symbol. Command can be:


    You can declare:


    Usually commands are:

IF ... ELSE ... END

    Each element of this construction should be closed with semicolon (;) too. Any quantity of any commands can be placed between elements, including nested IF ... ELSE ... END and WHILE ... END. For example:

"...; ...;"+
"IF nVar1>nVar2;"+
    "nVar3 = nVar1;"+
    "IF sVar.Lenght > 10;" +
        "sVar = sVar.ToUpper().Trim();" +
        "sVar = sVar.ToLower().Trim();" +
"ELSE;" +
    "nVar3 = nVar2;"+
    "IF sVar.Lenght > 10;" +
        "sVar = sVar.ToLower().Trim();" +
        "sVar = sVar.ToUpper().Trim();" +
"END;" +
"...; ...;"


    Each element of this construction should be closed with semicolon (;) too. Any quantity of any commands can be placed between elements, including nested WHILE ... END and IF ... ELSE ... END. For example:

"...; ...;" +
"IF nVar1>nVar2;"+
    "While nVar1>nVar2;"+
        "nVar1 = nVar1-1;" +
        "IF nVar1.ToString().Length>3;" +
             "nVar1=nVar1/2;" +
         "END;" +
    "While nVar1<nVar2;"+
        "nVar2 = nVar2-1;" +
        "IF nVar2.ToString().Length>3;" +
             "nVar2=nVar2/2;" +
         "END;" +
"...; ...;"

? directive

    Class Does has a field Console of type:

public interface IDOESConsole
    void Write(String _val);

    If you create an object which inherits this interface and store the reference to this object to Does.Console field, then you can use directive ? to write e result of expression onto your console. See script example above.


    If a command of DOES.NET script begins with // symbols then Does.Execute accepts this command as comments and does nothing.

DOES.NET functions

    DOES.NET functions can be public if declared in root stack level and private (if declared in stack sublevels). Private functions will be released after script executing by Does.Execute(sScript).

Declaring in C# code.

    Public functions can be declared before scripts executions with using method of Does class:

public bool DeclareFunction( String Name, String [] Args, String Code)

    First parameter is a function name.

    Second parameter is a list of names of arguments (just names).

    Third parameter is a script of function body.

    For example:

oDoes. DeclareFunction("Func1",new String [3] {"Parm1","Parm2","Parm3"}, "If Parm2>Parm3; Return Parm1-Parm2; Else; Return Parm1-Parm3;" );
oDoes. DeclareFunction("Func2",new String [3] {"Parm1","Parm2","Parm3"}, "If Parm2>Parm3; Return Parm1-Parm3; Else; Return Parm1-Parm2;" );
"While Func1(nVar1,nVar2,nVar3)>0;" +
    "nVar1=Func2(i,nVar2,nVar3)-i;" +

Declaring in DOES.NET script.

    Public and private functions can be declared right in script during executing. Function declarations should be placed in beginning of script before lines of script. Each function declaration should be ended with EndFunc directive. For example:

"Function Func1(Parm1,Parm2,Parm3);" +
    "If Parm2>Parm3;"+
        "Return Parm1-Parm2;"+
        "Return Parm1-Parm3;" +
"Function Func2(Parm1,Parm2,Parm3);" +
    "If Parm2>Parm3;"+
        "Return Parm1-Parm3;"+
        "Return Parm1-Parm2;" +
"nVar1=10;nVar2=20;nVar3=30;i=1000;" +
"While Func1(nVar1,nVar2,nVar3)>0;" +
    "nVar1=Func2(i,nVar2,nVar3)-i;" +


    Use Return command to return value from function. For example: "Return Parm1-Parm3;"

    Return value is also placed into variable with name ReturnValue in parent function or script (which calls current function).


DOES.NET Explorer (WPF).

    To use DOES.NET Explorer you should:


    < UserControl x :Class ="DOESTest.MainPage"
        xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns :x ="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns :d ="http://schemas.microsoft.com/expression/blend/2008"
        xmlns :de ="clr-namespace:DOESExplSL;assembly=DOESExplSL"
        xmlns :mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc :Ignorable ="d"
        d :DesignHeight="350" d :DesignWidth ="525">
        < Grid x :Name="LayoutRoot" Background ="White">
            < de:DOESExplorer Name ="Explorer"></de:DOESExplorer >
        </ Grid >
    </ UserControl >

    or in C#:

public partial class MainPage : UserControl
    public Grid MGrid = new Grid ();
    public DOESExplorer Explorer = new DOESExplorer();
    public MainPage()
        this .Content = MGrid;

    !!! DOES Explorer creates new Does class object as internal field! You should pass a reference to existing Does class object as parameter into DOESExplorer(Does _ds) constructor to explore this Does class object!     DOES Explorer window code looks like:

public class DOESWindow : ChildWindow
    public Grid MGrid = new Grid ();
    public DOESExplorer Explorer;
    public MainPage(Does _ds)
        Explorer = new DOESExplorer(_ds);
        this .Content = MGrid;

    After this you can call DOESExplorer as children window from your code and can pass working oDoes instance to explore and trace.

DOES Window DExpl = new DOESWindow(oDoes);

    DOES Explorer consists of four pages:

    In page with objects you can create new objects of specified type and can select from list of assemblies and types ( "New..." button to call list of assemblies).

    In page with functions you can just list functions and see their code.

    In "Expression" page you can write any DOES.NET expression, evaluate it and watch the results of evaluations.

    Main page is "Script" page. In this page you can:

Calling on error.

    If you have created DOES Explorer as children window then you can call it when error occurs during script executing and see what are problems. For example:

oDoes.Execute( " ...script..." );
if (oDoes.ErrorCode != 0)
    DOES Window DExpl = new DOESWindow(oDoes);


Debugging DOES.NET scripts (WPF).

    You can call script debugger from DOES Explorer by "Begin trace" button or in code of your NET program.

    Class Does has field Trace of interface

public interface IDOESTrace
    int Step( String Prg, int i);

    There is a class DOESTrace declared in DOESExplWPF.dll which implements IDOESTrace and you can create object of this type and can call to debug from your code. Create object of type DOESTrace and store reference to this object into Does.Trace before Does.Execute call. Does.Execute calls trace window on each line of your script.

    Syntax is:

    oDoes.Trace = new DOESTrace (oDoes); // pass oDoes object as parameter into constructor!
    oDoes.Execute(" ... script ... ");



Internal details.

    System.Type class and System.Reflection namespace allow to work with types and their members. We use these means as base of DOES.NET technology. Second part of technology is name tables. This part was inherited from other dynamic languages like FoxPro. And third part is a simple interpreter with minimal abilities, but a set of abilities is sufficient to create any dynamic code (scripts and expressions) except type declaration. We had to mix syntax C# and VFP to create DOES.NET script syntax and we tried to create this syntax most simple. But some internal details, described in this part of documentation, can be useful to implement more complex solutions with using DOES.NET

Name tables.

    DOES.NET uses internal tables to store references to dynamic objects and functions and their names. We call them "name tables" (inherited from FoxPro). On each level of stack DOES.NET creates two name tables for objects and functions. A length of each type of name table depends on stack level (root or not) and Does class properties:

public int PublicObjectsDefault = 5000 ;
public int PrivateObjectsDefault = 5000 ;
public int PublicFunctionsDefault = 1000 ;
public int PrivateFunctionsDefault = 1000 ;
public int MaxStackLevels = 1000 ;

    You can change a default sizes of table before oDoes.Init() method call. But the size of table is not fixed, and DOES.NET can expand table dimensions if size is exceeded.

    When you declare new object or function then DOES.NET does:

Object tables.

    Each element of stack (each level) has objects name table as field

public class DOESStackElement
public String Function = "" ;
public ObjectTable Objects;
public FunctionTable Functions;

    Each element of objects name table keeps: a name of object, reference to object and "local" status.

public class DOESNameTableElement
public String Name = "" ;
public Object Object = null ;
public bool Local = false ;

    To clear object DOES.NET just replace a reference to name-table-element and object with null. Further just NET FrameWork knows how and when to free memory (if there are no other references to this object). So, you have to control objects life time by yourself if needed (for example with usingIDisposable interface).

Function tables.

    Function name table is similar to object name table. But element of function-name-table keeps: the name of function, list of argument names and script of function body as string.

Table[i].Name = Name;
Table[i].Object = new DOESFunction (Parms, Code);
Table[i].Local = Local;
public class DOESFunction
public String [] ParamNames;
public String Code;
public DOESFunction( String [] _ParamNames, String _Code) { ParamNames = _ParamNames; Code = _Code; }
public String GetParmStr()


  Each element of stack (each level) has a structure.

public class DOESStackElement
public String Function = "" ;
public ObjectTable Objects;
public FunctionTable Functions;

    Size of stack table is fixed! (1000 levels) If a size of stack table is exceeded during next function call, then DOES.NET doesn'texpand stack table. So if you plan more nested calls then increase

Does.MaxStackLevels property before Does.Init() call.

"Does" class members.


Bigger or bigger public static Object Bigger(Object _val1, Object _val2)
public static Object bigger(Object _val1, Object _val2)

Returns first argument if it bigger than second, else returns second.

public bool Declare(String Name)     Declares private dynamic object with name Name and null value.
public bool Declare(String Name, Object Value)     Declares private dynamic object with name Name and assigns Value.
DeclareFunction public bool DeclareFunction(String Name, String[] Args, String Code)    Declares dynamic function with name Name, list of arguments Args and body script Code.
DeclareLocal public bool DeclareLocal(String Name)     Declares local dynamic object with name Name and null value.
public bool DeclareLocal(String Name, Object Value)     Declares local dynamic object with name Name and assigns Value.
DeclarePublic public bool DeclarePublic(String Name)     Declares public dynamic object with name Name and null value
public bool DeclarePublic(String Name, Object Value)    Declares public dynamic object with name Name and assigns Value.
DoCmd public Object DoCmd(String Cmd)    Executes single command. In difference to expression evaluation command can be assignment and can have left and right sides.
Evaluate public Object Evaluate(String Expr)     Executes expression and returns result.
Execute public Object Execute(ref String Script)
public Object Execute(String Script)

Executes script. Script is a set of commands.

Iif or iif public static Object Iif(bool Cond, Object iftrue, Object iffalse)
public static Object iif(bool Cond, Object iftrue, Object iffalse)

Returns second argument if first argument is true else returns third argument.

Init public bool Init()    Initializes Does class object. Should be called before Does class object using. You can change default values of properties PublicObjectsDefault , PrivateObjectsDefault, PublicFunctionsDefault, PrivateFunctionsDefault and MaxStackLevels   before Init().
Get public Object Get(String Name)    Returns value of dynamic object by name.
New public Object New(String Type)    Creates and returns object of specified type Type . Type is full name of type in assembly.
Not or not public static bool Not(Object _val)
public static bool not(Object _val)

Negation. Unary operation. Boolean inversion.

Release public void Release(String Name)    Deletes dynamic object. Name can be mask like *mask, mask* or *mask*, or name of object.
Set public bool Set(String Name, Object Value)     Replaces value of dynamic object with name Name with reference to object Value. If dynamic object with name Name doesn't exist then private object with this name will be created.
Smaller or smaller public static Object Smaller(Object _val1, Object _val2)
public static Object smaller(Object _val1, Object _val2)

Returns first argument if it smaller than second else returns second argument

Properties and fields:

Console public IDOESConsole Console   Replace this field with reference to IDOESConsole object to use output values by ? directive.
ErrorCode public int ErrorCode    Check after Does.Execute() , Does.DoCmd() and Does.Evaluate() . If there are no errors then Does.ErrorCode is 0. Else has a code of error.
ErrorFunction public String ErrorFunction    The name of function where error occurred.
ErrorException public Exception ErrorException      Exception object if unhandled error occurred.
ErrorLine public int ErrorLine    Line of script or function where error occurred.
ErrorMessage public String ErrorMessage      Error message.
MaxStackLevels public int MaxStackLevels = 1000;     A length of stack. Change this value if needed but before Does.Init() call.
PrivateFunctionsDefault public int PrivateFunctionsDefault = 1000;      A default length of private functions name tableChange this value if needed but before Does.Init() call.
PrivateObjectsDefault public int PrivateObjectsDefault = 5000;      A default length of private objects name tableChange this value if needed but before Does.Init() call.
PublicFunctionsDefault public int PublicFunctionsDefault = 1000;     A default length of public functions name table.  Change this value if needed but before Does.Init() call.
PublicObjectsDefault public int PublicObjectsDefault = 5000;     A default length of public objects name table.  Change this value if needed but before Does.Init() call.
Stack public DOESStackElement[] Stack;      Stack table.
StackLevel public int StackLevel      Current level of stack.
Trace public IDOESTrace Trace    Replace this field with reference to DOESTrace object to begin a debugging on Does.Execute() call.