Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net: Marshaling of function arguments #4044

Merged
merged 19 commits into from
Dec 11, 2023

Conversation

SergeyMenshykh
Copy link
Member

@SergeyMenshykh SergeyMenshykh commented Dec 6, 2023

This PR changes the way function arguments are marshalled to function parameters.

Currently, the marshaling process passes arguments of non-string types as they are to the MethodInfo.Invoke. String arguments are marshaled through .NET type converters, such as BooleanConverter, Int32Converter, etc., which convert the string arguments to the target types of method parameters. Additionally, if no suitable converter can be found to convert a string to the target type, the current marshaling mechanism checks if the target type has a type converter registered through the TypeConverterAttribute and use it.

Even though the mechanism works today, it has a few limitations:

  • Implicit casting/conversion is available for primitives only. Conversions such as int to long and float to double work out of the box because they are supported by the runtime. However, slightly complex conversions like guid to string or enum to int are not supported and require additional handling.
  • Data converters for custom types, registered through TypeConverterAttribute, are only supported for string arguments and not for non-string ones. This is because string arguments undergo custom marshaling that respects the attribute, while non-string arguments are handled by the runtime, which does not take it into account.

To overcome the limitations, this PR applies custom marshaling to all arguments of string type and non-string types. The custom marshaling relies on the data type converter mentioned above and respects the TypeConverterAttribute. Moreover, it leverages type converters to support conversions such as guid to string or enum to int.

Update: An interesting side effect was discovered during the implicit conversion from a double argument to an int parameter using the System.ComponentModel.DoubleConverter.ConvertTo method. Instead of casting the 99.9 double value to a 99 int value, it rounded it up to 100. The fix is simple - ensure that the argument types match the parameter types.

@shawncal shawncal added the .NET Issue or Pull requests regarding .NET code label Dec 6, 2023
@shawncal shawncal added the kernel Issues or pull requests impacting the core kernel label Dec 7, 2023
@SergeyMenshykh SergeyMenshykh changed the title .Net: POC of function arguments marshaling .Net: Marshaling of function arguments Dec 8, 2023
@markwallace-microsoft markwallace-microsoft added the v1.0.1 Required for the Semantic Kernel v1.0.1 release label Dec 11, 2023
@SergeyMenshykh SergeyMenshykh added this pull request to the merge queue Dec 11, 2023
Merged via the queue into main with commit 48c7c8d Dec 11, 2023
18 checks passed
@SergeyMenshykh SergeyMenshykh deleted the function-arguments-type-marshaling branch December 11, 2023 10:42
Kevdome3000 pushed a commit to Kevdome3000/semantic-kernel that referenced this pull request Dec 11, 2023
This PR changes the way function arguments are marshalled to function
parameters.

Currently, the marshaling process passes arguments of non-string types
as they are to the `MethodInfo.Invoke`. String arguments are marshaled
through .NET type converters, such as `BooleanConverter`,
`Int32Converter`, etc., which convert the string arguments to the target
types of method parameters. Additionally, if no suitable converter can
be found to convert a string to the target type, the current marshaling
mechanism checks if the target type has a type converter registered
through the `TypeConverterAttribute` and use it.

Even though the mechanism works today, it has a few limitations:
- Implicit casting/conversion is available for primitives only.
Conversions such as int to long and float to double work out of the box
because they are supported by the runtime. However, slightly complex
conversions like guid to string or enum to int are not supported and
require additional handling.
- Data converters for custom types, registered through
`TypeConverterAttribute`, are only supported for string arguments and
not for non-string ones. This is because string arguments undergo custom
marshaling that respects the attribute, while non-string arguments are
handled by the runtime, which does not take it into account.

To overcome the limitations, this PR applies custom marshaling to all
arguments of string type and non-string types. The custom marshaling
relies on the data type converter mentioned above and respects the
`TypeConverterAttribute`. Moreover, it leverages type converters to
support conversions such as guid to string or enum to int.

Update: An interesting side effect was discovered during the implicit
conversion from a double argument to an int parameter using the
`System.ComponentModel.DoubleConverter.ConvertTo` method. Instead of
casting the 99.9 double value to a 99 int value, it rounded it up to
100. The fix is simple - ensure that the argument types match the
parameter types.

(cherry picked from commit 48c7c8d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kernel Issues or pull requests impacting the core kernel .NET Issue or Pull requests regarding .NET code v1.0.1 Required for the Semantic Kernel v1.0.1 release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants