View Page Source

Back to Page
Revision 9 (current)
Edited by feos on 1/2/2022 3:44 PM
Original article:
* https://www.red-gate.com/simple-talk/dotnet/net-framework/dynamic-language-integration-in-a-c-world/
Pythonnet:
* https://pypi.org/project/pythonnet/


%%TOC%%


!!! Calling C# Methods from Python

In the following example, I’ll perform the reverse operation; creating the calculator’s class in C# and then accessing it from Python. There is no attached demonstration for this, and it does not significantly inform the final build of the application, so this is primarily an academic exercise.


!! Create the C# Class

1. In Visual Studio, create a new C# Class Library project with the name __DynamicCS__;

2. Create a standard C# class in the __DynamicCS__ project by renaming the existing __Class1.cs__ class to __Calculator.cs__. Implement two simple methods for adding and subtracting numbers, as follows:

%%SRC_EMBED c
using System;

namespace DynamicCS
{
    public class Calculator
    {
        public double add(double argA, double argB)
        {
            return argA + argB;
        }
        public double sub(double argA, double argB)
        {
            return argA - argB;
        }
    }
}
%%END_EMBED

The __Calculator__ class is a valid C# class, but to access it as a dynamic object from Python, you need to have a wrapper class that inherits from DynamicObject, as demonstrated over the remaining steps:

3. In the Solution Explorer, right-click the DynamicCS project file, and select __Add > New Item > Class__;

4. In the Solution Explorer, rename the new file to __DynamicCalc.cs__;

5. In the newly-created class, add:

%%SRC_EMBED c
using System.Dynamic
%%END_EMBED

6. Define a public __DynamicCalc__ class that derives from __DynamicObject__:

%%SRC_EMBED c
public class DynamicCalc: DynamicObject
%%END_EMBED

7. Implement the constructor of the __DynamicCalc__ class: 

%%SRC_EMBED c
public DynamicCalc()
{
    calc = new Calculator();
}
%%END_EMBED

8. Override methods from the __DynamicObject__ class. In the presented example, the __TryGetMember__ method has to be overridden, at the very least:

%%SRC_EMBED c
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
}
%%END_EMBED

9. The resulting __DynamicCalc.cs__ file might look like this: 

%%SRC_EMBED c
namespace DynamicCS
{
    public class DynamicCalc: DynamicObject
    {
        Calculator calc;
        public DynamicCalc()
        {
            calc = new Calculator();
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = null;
            switch (binder.Name)
            {
            case "add":
                result = (Func<double, double, double>) ((double a, double b)
                    => calc.add(a, b));
                return true;
            case "sub":
                result = (Func<double, double, double>) ((double a, double b)
                    => calc.sub(a, b));
                return true;
            }
            return false;
        }
    }
}
%%END_EMBED

Note that, in the __TryGetMember__ method:
* __binder.Name__ represents a name of the method or property called; 
* __result__ is an output value of the method or property. In this case, it is a delegate to the ‘add’ and ‘sub’ methods of the calc object; 
* __return__ should return ‘true’ if the operation is successful, otherwise ‘false’. 

Finally, save and build the solution. The Python executable performs the calculations by calling the calc object, which in turn resolves the result of the C# __DynamicCalc__ class, imported from __DynamicCS.dll__.


!! Call the C# Methods from Python

1. In the Solution Explorer, right click the __DynamicCS__ project file, and select __Add > New Item > Text file__;

2. In the Solution Explorer, rename the new file to __client.py__;

3. Add an __import sys__ statement, pointing to the directory where your C# DLL is located.  In this example, I have saved __DynamicCS.dll__ in ''C:\MyProjects\DynamicCS\DynamicCS\bin\Debug'': 

%%SRC_EMBED python
import sys
sys.path.append(r"C:\MyProjects\DynamicCS\DynamicCS\bin\Debug")
%%END_EMBED

4. Reference your C# DLL: 

%%SRC_EMBED python
import clr
clr.AddReference(r"DynamicCS.dll")
%%END_EMBED

5. Create a Python object as you would for any other object, then use it to perform some calculations: 

%%SRC_EMBED python
from DynamicCS import DynamicCalc
calc=DynamicCalc()
%%END_EMBED

6. The resulting __client.py__ file might look like this: 

%%SRC_EMBED python
import sys
sys.path.append(r"C:\MyProjects\DynamicCS\DynamicCS\bin\Debug")

import clr
clr.AddReference(r"DynamicCS.dll")

from DynamicCS import DynamicCalc

calc=DynamicCalc()

print calc.__class__.__name__
# display the name of the class: 'DynamicCalc' 

a=7.5
b=2.5

res = calc.add(a, b)
print a, '+', b, '=', res

res = calc.sub(a, b)
print a, '-', b, '=', res

raw_input('Press any key to finish...')
%%END_EMBED

7. Save and run the Python client. 

[https://i.imgur.com/jUwq8pd.gif]
* Figure 2. The basic calculator, implemented mostly in Python. Creating and calling Python methods in C#

The Python executable performs the calculations by calling the __calc__ object, which in turn resolves the result of the C# __DynamicCalc__ class, imported from __DynamicCS.dll__. The end result looks much the same as the earlier implementation.