.Net Runtime Library for Delphi
Close
Create Instance of .Net Objects

In order to interact with .Net Objects's methods, properties, Fields and events, you need to create an instance of the object. There are several ways to Create an Instance of a .Net Object in Delphi using the Delphi Framework Library (DFL). These are:

  • Using Reflection
  • Using Common Language Runtime Object (ClrObject)
  • Using Constructor CoClasses

Using Reflection to Create instance of .Net Objects

There are several classes and methods that can be used to create instances of .Net Objects. The mechanism used to create these instances is through reflection. For more information about using Reflection in Delphi using DFL. For more information, see Reflection Overview.

The following methods can be used to create instances of .Net Objects through reflections:

Delphi
program AppDomainCreateInstance; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var CurrentAppD: TClrAppDomain; ObjHandle: _ObjectHandle; ObjUnwrap: Variant; begin CurrentAppD := TClrAppDomain.GetCurrentDomain; ObjHandle := CurrentAppD.CreateInstance('MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null', 'MyType'); ObjUnwrap := ObjHandle.Unwrap_; end.















Delphi
program AppDomainCreateInstanceFrom; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var CurrentAppD: TClrAppDomain; ObjHandle: _ObjectHandle; ObjUnwrap: Variant; begin CurrentAppD := TClrAppDomain.GetCurrentDomain; ObjHandle := CurrentAppD.CreateInstanceFrom('C:\Temp\Mathematics.dll', 'MyType'); ObjUnwrap := ObjHandle.Unwrap_; //Note the ObjectHandle.Unwrap is different from ObjectHandle.Unwrap_. //The Unwrap method returns the original .Net ObjectHandle object whereas the //Unwrap_ returns the .net wrapped object end.






  • TClrAppDomain.CreateComInstanceFrom: This method creates a new instance of a specified COM type. Parameters specify the name of a file that contains an assembly containing the type and the name of the type.
Delphi
program AppDomainCreateComInstanceFrom; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var CurrentAppD: TClrAppDomain; ObjHandle: _ObjectHandle; ObjUnwrap: Variant; begin CurrentAppD := TClrAppDomain.GetCurrentDomain; ObjHandle := CurrentAppD.CreateComInstanceFrom('MyCOM_Assembly, version=1.2.3.4, culture=neutral, publicKeyToken=null', 'MyType'); ObjUnwrap := ObjHandle.Unwrap_; //Note the ObjectHandle.Unwrap is different from ObjectHandle.Unwrap_. //The Unwrap method returns the original .Net ObjectHandle object whereas the //Unwrap_ returns the .net wrapped object end






  • All Create Instance Methods in TClrActivator class: The class contains methods to create types of objects locally or remotely, or obtain references to existing remote objects.
Delphi
program ActivatorCreateInstance; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core, CNClrLib.EnumTypes; var Obj: Variant; ObjHandle: _ObjectHandle; ClrObject: _ClrObject; begin //This method create Instance of ArrayList type by name using that type's default constructor Obj := TClrActivator.CreateInstance('System.Collections.ArrayList'); //This method creates an instance of the ArrayList type by name using the constructor that best matches the specified parameters. //In this case the parameter is an integer, hence the ArrayList Constructor with Capacity as parameter will be invoked. Obj := TClrActivator.CreateInstance('System.Collections.ArrayList', [10]); //Same as above except this method accepts _ObjectArray Obj := TClrActivator.CreateInstance('System.Collections.ArrayList', TClrArrayHelper.ToObjectArray([10])); //This method create Instance of ArrayList type using that type's default constructor Obj := TClrActivator.CreateInstance(TClrAssembly.GetType('System.Collections.ArrayList')); //This method creates an instance of the ArrayList type using the constructor that best matches the specified parameters. //In this case the parameter is an integer, hence the ArrayList Constructor with Capacity as parameter will be invoked. //A Binding attribute is part of the method definition which controls the binding and the //way in which the search for members and types is conducted by reflection. Obj := TClrActivator.CreateInstance(TClrAssembly.GetType('System.Collections.ArrayList'), [10], [bfInstance, bfPublic], nil); //This method creates an instance of the type whose name is specified, using //the named assembly file and the constructor that best matches the specified parameters. //A Binding attribute is part of the method definition which controls the binding and the //way in which the search for members and types is conducted by reflection. ObjHandle := TClrActivator.CreateInstanceFrom('C:\Temp\Mathematics.dll', 'SumData', True, [bfInstance, bfPublic], nil, TClrArrayHelper.ToObjectArray([2, 5])); Obj := ObjHandle.Unwrap_; //This method creates an instance of the COM object whose name is specified. ObjHandle := TClrActivator.CreateComInstance('MyCOM_Assembly, version=1.2.3.4, culture=neutral, publicKeyToken=null', 'MyType'); Obj := ObjHandle.Unwrap_; //Create an Instance of ArrayList type by name with no parameter and return ClrObject ClrObject := TClrActivator.ClrCreateInstance('System.Collections.ArrayList'); Obj := ClrObject.Unwrap; end.















  • All the Methods in TClrDispatchActivator Class : The class contains methods to create types of objects and return type will be Dispatch Interface instaed of Unknown Variant (IUnknown). These create instance methods in this class are required if you want ot create a library in .net with DispIDs and access them directly in delphi using dispinterfaces. For more information see Access External .Net Types using COM Dispatch.
Delphi
program DispatchActivatorCreateInstance; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var Obj: IDispatch; begin //This method create Instance of ArrayList type by name using that type's default constructor Obj := TClrDispatchActivator.CreateInstance('System.Collections.ArrayList'); //This method creates an instance of the ArrayList type by name using the constructor that best matches the specified parameters. //In this case the parameter is an integer, hence the ArrayList Constructor with Capacity as parameter will be invoked. Obj := TClrDispatchActivator.CreateInstance('System.Collections.ArrayList', [10]); //Same as above except this method accepts _ObjectArray Obj := TClrDispatchActivator.CreateInstance('System.Collections.ArrayList', TClrArrayHelper.ToObjectArray([10])); end.






  • TClrAssembly.CreateInstance: This method locates a type from the assembly loaded and create an instance of it using the system activator.
Delphi
program AssemblyCreateInstance; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core, CNClrLib.EnumTypes; var Obj: Variant; AAsm: TClrAssembly; begin //Load an assembly file AAsm := TClrAssembly.LoadFrom('C:\Temp\Mathematics.dll'); //Create the specified type from this assembly and creates an instance of the type by name //with optional case-sensitive search, arguments, and binding. Obj := AAsm.CreateInstance('Mathematics.MathsData', True, [bfInstance, bfPublic, bfIgnoreCase], TClrArrayHelper.ToObjectArray([10])); end.








Using Common Object Runtime Object (ClrObject) to create and wrap .Net Object

This is a wrapper interface which provides low-level services to all interfaces defined in the Delphi Framework Library and .net objects. The ClrObject interface has methods and properties which allows you to interact with the properties, fields, events and methods of the object to which the interface is wrapped. The process of retrieving the members of the internal object is smooth and fast. For more information see How to Use ClrObject Interface. There are 2 ways to create instances of .Net Objects using the ClrObject. These are:

C#
//Assuming I have a C# Class which looks like this:; // ================================================= //Compiled To: Mathematics.dll using System; using System.Runtime.InteropServices; namespace Mathematics { public class Mathematics { public Mathematics() { } public bool IgnoreError { get; set; } public int Add(int a, int b) { return a + b; } public int Subtract(int a, int b) { return a - b; } public bool Equal(int a, int b) { return a == b; } } }









Delphi
program MathematicDLLDemo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; //Delphi Representation of the above C# Class will look like below: type TMathematics = class(TClrBaseObject) private function GetIgnoreError: Boolean; procedure SetIgnoreError(Value: Boolean); public constructor Create; //Default Constructor; Destructor Destroy; override; function Add(A, B: Integer): Integer; function Subtract(A, B: Integer): Integer; function Equal(A, B: Integer): Boolean; property IgnoreError: Boolean read GetIgnoreError write SetIgnoreError; end; { TMathematics } function TMathematics.Add(A, B: Integer): Integer; begin Result := InvokeMethod('Add', 'System.Int32;System.Int32', [A, B]); end; constructor TMathematics.Create; begin inherited Create('Mathematics.Mathematics', nil); //Note: I am not using 'inherited Create('Mathematics.Mathematics')' //because the class is not static; end; destructor TMathematics.Destroy; begin inherited; end; function TMathematics.Equal(A, B: Integer): Boolean; begin Result := InvokeMethod('Equal', ['System.Int32', 'System.Int32'], [A, B]); end; function TMathematics.GetIgnoreError: Boolean; begin Result := GetPropertyValue('IgnoreError'); end; procedure TMathematics.SetIgnoreError(Value: Boolean); begin SetPropertyValue('IgnoreError', Value); end; function TMathematics.Subtract(A, B: Integer): Integer; begin Result := InvokeMethod('Subtract', 'System.Int32;System.Int32', [A, B]); end; var AMaths: TMathematics; Console: _Console; begin Console := CoConsole.CreateInstance; //Load Assembly into the current Domain //Make sure the dll is in the same location as the EXE. If you want to store //the dll in a separate location, make sure you provide the full path of the dll. TClrAssembly.LoadFrom('Mathematics.dll'); AMaths := TMathematics.Create; try Console.WriteLine_15('Add(30, 50): {0}', AMaths.Add(30, 50)); Console.WriteLine_15('Subtract(30, 50): {0}', AMaths.Subtract(30, 50)); Console.WriteLine_15('Equal(30, 50): {0}', AMaths.Equal(30, 50)); Console.WriteLine_15('Equal(50, 50): {0}', AMaths.Equal(50, 50)); Console.WriteLine_15('IgnoreError: {0}', AMaths.IgnoreError); Console.WriteLine; Console.WriteLine_14('Set IgnoreError to True'); AMaths.IgnoreError := True; Console.WriteLine_15('IgnoreError: {0}', AMaths.IgnoreError); finally AMaths.Free; end; Console.ReadKey; end. //Output //Add(30, 50): 80 //Subtract(30, 50): -20 //Equal(30, 50): False //Equal(50, 50): True //IgnoreError: False //Set IgnoreError to True //IgnoreError: True





  • Use the ClrObject Interface to create wrapper instance of the original object to allow easy access and interactions to the objects members (Fields, Properties, Members, and Events etc.).
Delphi
program MathematicDLLDemo2; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core; var Console: _Console; AMaths: TClrObject; clrObject: _ClrObject; begin Console := CoConsole.CreateInstance; TClrAssembly.LoadFrom('Mathematics.dll'); //Create an instance of the Mathematics type in the Mathematics.dll and wrap it as ClrObject clrObject := CoClrObject.CreateInstance(TClrAssembly.GetType('Mathematics.Mathematics'), nil); AMaths := TClrObject.Create(clrObject); try Console.WriteLine_15('Add(30, 50): {0}', AMaths.InvokeMethod('Add', 'System.Int32;System.Int32', [30, 50])); Console.WriteLine_15('Subtract(30, 50): {0}', AMaths.InvokeMethod('Subtract', 'System.Int32;System.Int32', [30, 50])); Console.WriteLine_15('Equal(30, 50): {0}', AMaths.InvokeMethod('Equal', 'System.Int32;System.Int32', [30, 50])); Console.WriteLine_15('Equal(50, 50): {0}', AMaths.InvokeMethod('Equal', 'System.Int32;System.Int32', [50, 50])); Console.WriteLine_15('IgnoreError: {0}', AMaths.GetPropertyValue('IgnoreError')); Console.WriteLine; Console.WriteLine_14('Set IgnoreError to True'); AMaths.SetPropertyValue('IgnoreError', True); Console.WriteLine_15('IgnoreError: {0}', AMaths.GetPropertyValue('IgnoreError')); finally AMaths.Free; end; Console.ReadKey; end. //Output //Add(30, 50): 80 //Subtract(30, 50): -20 //Equal(30, 50): False //Equal(50, 50): True //IgnoreError: False //Set IgnoreError to True //IgnoreError: True




Using Constructor CoClasses

There are several classes defined in the Runtime library for creating instances of the .net framework types. These classes are called CoClasses. For example, to create an instance of System.io.FileStream(string path, FileMode mode) using Delphi Framework Library (DFL), use the equivalent interface of System.io.FileStream which is _FileStream defined in DFL to create an instance of the _FileStream using the FileStream coClass called coFileStream class. The class has static methods called CreateInstance and each method represent the constructors defined for the System.io.FileStream. For more information see Constructor Classes.

The following code example shows how to write data to a file, byte by byte, and then verify that the data was written correctly using _FileStream Interface.

Delphi
program FStream; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core, CNClrLib.Enums, CNClrLib.EnumTypes, CNClrLib.IO; const fileName = 'Test#@@#.dat'; var Console: _Console; dataArray: _ByteArray; random: _Random; fileStream: _FileStream; I: Integer; begin //Create static instance of the System.Console class in Delphi using DFL Console := CoConsole.CreateInstance; // Create random data to write to the file. dataArray := CoByteArray.CreateInstance(100000); random := CoRandom.CreateInstance; random.NextBytes(dataArray); //Create an instance of the FileStream using CoClass of the FileStream called coFileStream; fileStream := CoFileStream.CreateInstance(fileName, fmCreate); // Write the data to the file, byte by byte. for I := 0 to dataArray.Length - 1 do fileStream.WriteByte(dataArray[I]); // Set the stream position to the beginning of the file. fileStream.Seek(0, SeekOrigin_Begin); try // Read and verify the data. for I := 0 to dataArray.Length - 1 do begin if dataArray[i] <> fileStream.ReadByte() then begin Console.WriteLine_14('Error writing data.'); exit; end; end; Console.WriteLine_15('The data was written to {0} and verified.', fileStream.Name); finally Console.ReadKey; end; end. //Output //The data was written to ..\Test#@@#.dat and verified.