Hello
The params
keyword is just a syntax sugar. The function in question still receives an array. So for the Delphi plugin the same method can be exposed as void SomeFunction(object[] args);
The second part is more complex. To mimic the object[]
behavior we need to be able to pass value and its type pairs from Delphi to .NET code.
There are 2 possible solutions. 1st is to define an interface that would expose Type and Value properties like
public interface IValue: IHYCrossPlatformInterface
{
int Type {get; set;}
int ValueAsInteger {get; set;}
double ValueAsDouble {get; set;}
string ValueAsString {get; set;}
bool ValueAsBool {get; set;}
}
Then expose a method like
void SomeFunction(IValue[] args)
in the plugin interface. This method should accept IValue[]
array, convert them to object[]
and call the “real” SomeMethod.
Implement this interface Delphi-side and you will be able to send any arbitrary sets of values.
This would work for a relatively rarely called methods, because marshalling such complex values and accessing them .NET-side will have its performance costs.
2nd approach requires more code but is way faster in terms of Delphi->.NET call.
The idea is to serialize the array of Variant values Delphi-side and to pass the entire array as a binary array from Delphi to .NET. So the plugin would expose method as
void SomeFunction(Byte[] args)
Delphi-side you will need a wrapper method accepting array of Variant
This method should do the following:
- Create new TMemoryStream instance
- Write array length as integer of the array to the stream
- For each array element
3.1. Write VarType
to the stream as integer
3.2. Write variant value to the stream. Integer and Double values can be written AS IS. For Boolean values write 1 for TRUE and 0 for FALSE. Fro String values convert them to Byte array using a call like TEncoding.Default.GetBytes(aValue)
and write down this array length and then the array itself
- Once the array is serialized convert stream to byte array and call the plugin method
- Put the received byte array into a MemoryStream instance and deserialize it back.
Some snippets to make this task easier:
Reading Int32 from stream:
Byte[] buffer = new Byte[4];
Int32 bytesRead = this.Stream.Read(buffer, 0, 4);
return buffer[0] + (buffer[1] * 0x100) + (buffer[2] * 0x10000) + (buffer[3] * 0x1000000);
Reading Double from stream:
Byte[] buffer = new Byte[8];
this.Stream.Read(buffer, 0, 8);
return System.BitConverter.ToDouble(buffer, 0);
Reading ANSI String from stream:
Int32 stringLength = ...read integer...
Byte[] buffer = new Byte[stringLength];
Int32 bytesRead = this.Stream.Read(buffer, 0, stringLength);
return Encoding.Default.GetString(buffer, 0, buffer.Length);
Thi approach requires more code, but its performance is way better. Serialization/Deserialization costs are way lover than the costs of a dozen COM interop calls required to read array in the 1st approach.
Regards