.Net Runtime Library for Delphi
Close
How to: Obtain Type and Member Information from an Assembly

The CNClrLib.Core.Intf namespace contains many methods for obtaining information from an assembly. This section demonstrates one of these methods. For additional information, see Reflection Overview.

The following example obtains type and member information from an assembly.

Example

Delphi
program Asminfo1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, CNClrLib.Host, CNClrLib.Core, CNClrLib.Enums; var Console: _Console; myType: _Type; I: Integer; MemberInfoArray: _MemberInfoArray; begin Console := CoConsole.CreateInstance; Console.WriteLine_14('Reflection.MemberInfo'); // Get the Type and MemberInfo. // Insert the fully qualified class name inside the quotation marks in the // following statement. myType := TClrAssembly.GetType('System.IO.BinaryReader'); MemberInfoArray := myType.GetMembers_1(BindingFlags_Public or BindingFlags_NonPublic or BindingFlags_Static or BindingFlags_Instance or BindingFlags_DeclaredOnly); // Get and display the DeclaringType method. Console.WriteLine_15('There are {0} documentable members in ', MemberInfoArray.Length); Console.WriteLine_15('{0}.', myType.FullName); for I := 0 to MemberInfoArray.Length - 1 do Console.WriteLine_14(MemberInfoArray[I].Name); Console.ReadKey; end. //Output //Reflection.MemberInfo //There are 43 documentable members in //System.IO.BinaryReader. //get_BaseStream //Close //Dispose //Dispose //PeekChar //Read //ReadBoolean //ReadByte //ReadSByte //ReadChar //ReadInt16 //ReadUInt16 //ReadInt32 //ReadUInt32 //ReadInt64 //ReadUInt64 //ReadSingle //ReadDouble //ReadDecimal //ReadString //Read //InternalReadChars //InternalReadOneChar //ReadChars //Read //ReadBytes //FillBuffer //Read7BitEncodedInt //.ctor //.ctor //.ctor //BaseStream //m_stream //m_buffer //m_decoder //m_charBytes //m_singleChar //m_charBuffer //m_maxCharsSize //m_2BytesPerChar //m_isMemoryStream //m_leaveOpen //MaxCharBytesSize













Accessing external .Net Library Type Objects
Unlike COM in Delphi which requires the .Net library classes to be marked with ComVisible attribute or the .Net Assembly to be marked as ComVisible and the .Net Library types to be registered, the .Net Runtime Library for Delphi behaves differently. Even though the same COM mechanism is used, it does not require marking the .Net classes or the assembly with ComVisible and no registration of the .Net library types are required. In order to access any external .Net library objects; firstly, the external library has to be loaded onto the runtime host AppDomain using the Load Assembly methods in the runtime host class or other means described in Section 3 above. Secondly, create an instance of the .Net type using the CreateInstance methods in the runtime host class or other means described in Section 4 above. Once the instance has been created successfully, there are 3 possible ways to access the methods and properties and perhaps the public fields of the object instance created. These are; using CNObject interface, using Reflection and using COM Dispatch Interface. There are three ways to access members of .net types: These are:
  • Using ClrObject Interface
  • Using Reflection Interfaces
  • Using COM Dispatch
Using ClrObject Interface
Common Language Runtime Object (ClrObject) interface or the wrapper class TClrObject has methods which allow you to retrieve and update object type field values, property values or invoke methods of the object type.
For more information, see Use ClrObject Interface .
Example in C#
C#
public Object this[Int32 index]
{
Get {...}
Set {...}
}

public bool IsData
{
Get {...}
Set {...}
}

public void GetData()
{
....
}

public void GetData(bool Accept)
{
....
}


To access the above properties and methods in delphi using ClrObject interface, see the example code below;
Delphi
var
clrObject: TClrObject;
Index0: OleVariant;
IsData: Boolean;
begin
//Assuming the TClrObject instance has been created

//Access the property indexer at position 0
Index0 := clrObject.GetPropertyValue('Item', 0);
//Or
Index0 := clrObject.GetPropertyValue('Item', 'System.Int32', 0);

//Access the property IsData
IsData := clrObject.GetPropertyValue('IsData');

//Set True to the property IsData
clrObject.SetPropertyValue('IsData', True);

//Invoke the parameterless method GetData
clrObject.InvokeMethod('GetData');

//Invoke the method GetData with parameter
clrObject.InvokeMethod('GetData', 'System.Boolean', [True]);
end;






Using Reflection Interfaces
Reflection is the ability of a code to read its own metadata for the purpose of finding assemblies, modules and type information at runtime. In other words, reflection provides objects that encapsulate assemblies, modules and types. A program reflects on itself by extracting metadata from its assembly and using that metadata either to inform the user or to modify its own behaviour. By using Reflection with the help of the Delphi Framework Library, one is able to find out details of an object, method, and create objects and invoke methods at runtime. The CNClrLib.Core.Intf namespace contains interfaces that provide a managed view of loaded types, methods, and fields, with the ability to dynamically create and invoke types. For more information, see Dynamic Programming using Reflection .
Example
Delphi
program Example;

{$APPTYPE CONSOLE}
{$R *.res}

uses
System.SysUtils,
CNClrLib.Host,
CNClrLib.Core;

var
Console: _Console;
ASQLCon: OleVariant;
ASQLConStr: WideString;
ASQLConType: _Type;
AConnProp: _PropertyInfo;
AOpenMeth,
ACloseMeth: _MethodInfo;
begin
Console := CoConsole.CreateInstance;
try
//Load Assembly by Partial Name(This load the assembly from the GAC)
Console.WriteLine_14('Load System.Data Assembly from the GAC. FileName: System.Data.dll');
TClrAssembly.LoadWithPartialName('System.Data');

//Create Instance of System.Data.SqlClient.SqlConnection Type
ASQLCon := TClrActivator.CreateInstance('System.Data.SqlClient.SqlConnection');

ASQLConStr := 'Data Source=myServerAddress;Initial Catalog= myDataBase;UserID=myUsername;Password=myPassword';
Console.WriteLine_15('Connecting to : {0}', ASQLConStr);

ASQLConType := TClrAssembly.GetObjectType(ASQLCon);
AConnProp := ASQLConType.GetProperty_6('ConnectionString');
AConnProp.SetValue_2(ASQLCon, ASQLConStr);

AOpenMeth := ASQLConType.GetMethod_5('Open');
AOpenMeth.Invoke_2(ASQLCon, nil);
Console.WriteLine_14('Connection Opened');

ACloseMeth := ASQLConType.GetMethod_5('Close');
ACloseMeth.Invoke_2(ASQLCon, nil);
Console.WriteLine_14('Connection Closed');
except
on E: Exception do
Console.WriteLine_15('Exception: {0}', E.Message);
end;
end.








Using COM Dispatch
This approach is the easiest and more flexible way of accessing external .Net library types by generating the class types in .Net library as a DispInterface type with user defined DispId. DispId is very important when using this approach to access methods and properties of the .Net external library types. Using the COM DispInterface, the coder does not need to register the .net libraries; however the .Net Class methods and properties should be marked with DispId attributes. You can either mark the .Net Class with ComVisible attribute and subsequently use the Type Library importer in Delphi to generate Delphi library version of the .Net Library or you can manually code a corresponding DispInterface type in Delphi making sure that the DispIds in the properties and methods of the .Net library is the same as the DispIds in the properties and methods of the corresponding Delphi DispInterface type. Form more information, See Access External .Net Types using COM Dispatch.
Assuming the following class is compiled into a Mathematics.dll in c#
C#
using System.Runtime.InteropServices;

namespace Mathematics
{
public class Mathematics
{
[DispId(0)]
public int Add(int a, int b)
{
return a + b;
}

[DispId(1)]
public int Subtract(int a, int b)
{
return a - b;
}

[DispId(2)]
public bool Equal(int a, int b)
{
return a == b;
}
}
}





You can create a corresponding dispatch interface of the c# mathematics class in the Mathematics.dll as follows:
Delphi
_Mathematics = dispinterface
['{D77959BD-C7AC-4D65-9980-A88510F776B8}']
function Add(a, b : Integer) : Integer; dispid 0;
function Subtract(a, b : Integer) : Integer; dispid 1;
function Equal(a, b : Integer) : WordBool; dispid 2;
end;


To create instance of the _Mathematics object and access the functions, see the code below:
Delphi
program MathematicsDemo;

{$APPTYPE CONSOLE}
{$R *.res}

uses
System.SysUtils,
CNClrLib.Host,
CNClrLib.Host.Helper,
CNClrLib.Core;

type
_Mathematics = dispinterface
['{D77959BD-C7AC-4D65-9980-A88510F776B8}']
function Add(a, b : Integer) : Integer; dispid 0;
function Subtract(a, b : Integer) : Integer; dispid 1;
function Equal(a, b : Integer) : WordBool; dispid 2;
end;

var
Console: _Console;
AMaths: _Mathematics;
begin
Console := CoConsole.CreateInstance;
try
//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');

//Create instance of the Mathematics Class
AMaths := _Mathematics(TClrDispatchActivator.CreateInstance('Mathematics.Mathematics'));

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));
except
on E: Exception do
Console.WriteLine_15('Exception: {0}', E.Message);
end;
end.

//Output

//Add(30, 50): 80
//Subtract(30, 50): -20
//Equal(30, 50): False
//Equal(50, 50): True