Instantiating a python class in C#
IronPython classes are not .NET classes. They are instances of IronPython.Runtime.Types.PythonType which is the Python metaclass. This is because Python classes are dynamic and support addition and removal of methods at runtime, things you cannot do with .NET classes.
To use Python classes in C# you will need to use the ObjectOperations class. This class allows you to operate on python types and instances in the semantics of the language itself. e.g. it uses the magic methods when appropriate, auto-promotes integers to longs etc. You can find out more about ObjectOperations by looking at the source or using reflector.
Here is an example. Calculator.py contains a simple class:
class Calculator(object):
def add(self, a, b):
return a + b
You can use it from your pre .NET 4.0 C# code like this:
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
ObjectOperations op = engine.Operations;
source.Execute(scope); // class object created
object klaz = scope.GetVariable("Calculator"); // get the class object
object instance = op.Call(klaz); // create the instance
object method = op.GetMember(instance, "add"); // get a method
int result = (int)op.Call(method, 4, 5); // call method and get result (9)
You will need to reference the assemblies IronPython.dll, Microsoft.Scripting and Microsoft.Scripting.Core.
C# 4 made this much easier with the new dynamic type.
ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
dynamic Calculator = scope.GetVariable("Calculator");
dynamic calc = Calculator();
int result = calc.add(4, 5);
If you are using Visual Studio 2010 or later with NuGet support simply execute this to download and reference the appropriate libraries.
Install-Package IronPython
Instantiating a python class from a module by full name
I've managed to write an extension class which would provide a similar functionality to a regular python's "from X import Y". In the end I had to use the default ImportModule to import the very root of the module hierarchy and traverse down the structure to find the necessary module:
private static PythonModule TraverseDown(PythonModule module, string moduleName)
{
return (PythonModule) module.Get__dict__()[moduleName];
}
private static PythonModule TraverseToTarget(ScriptScope scope, string moduleName)
{
// The root of the module was already imported by the engine's import module call.
var moduleNameParts = moduleName.Split('.').Skip(count: 1).ToList();
var rootModule = scope.GetVariable<PythonModule>(moduleNameParts.First());
return moduleNameParts.Skip(count: 1).Aggregate(rootModule, TraverseDown);
}
public static dynamic ImportFromModule(this ScriptEngine engine, string moduleName, string targetImport)
{
var rootModuleScope = engine.ImportModule(moduleName);
var targetModule = TraverseToTarget(rootModuleScope, moduleName);
return targetModule.Get__dict__()[targetImport];
}
Here's how one is supposed to use this extension:
// Here's a sample input:
var moduleName = "sp.content.abilities.torpedo"
var className = "AbilityTorpedo"
// Here's my module loading and class instaitiation
var moduleScope = ScriptEngine.ImportFromModule(moduleName, className);
return ScriptEngine.Operations.CreateInstance(scriptClass);
How to store subclass types and be able to instantiate a variable with the position of the list?
In order to use Activator.CreateInstance(someType)
each type must have a parameterless constructor. You indicated that sometimes you get an error, so it's apparent that some of your classes don't. Even if they did that's a difficult design because later you might want to add a type without a default constructor and you won't be able to.
One approach is to create a list of instantiated classes instead of a list of types.
Instead of this:
List<Type> executionsTypes = new List<Type>();
executionsTypes.Add(typeof(Affectation));
executionsTypes.Add(typeof(Pass));
do this:
List<Execution> executions = new List<Execution>();
executions.Add(new Affectation());
executions.Add(new Pass());
Then instead of selecting a type from the list and having to instantiate it, you can select a class instance that's already been instantiated.
What if you don't want to re-use class instances and you need a new one each time? Then you could do this:
List<Func<Execution>> executions = new List<Func<Execution>>();
executions.Add(() => new Affectation());
executions.Add(() => new Pass());
executions.Add(() => new SomeTypeWithParameters("x", 1));
Then what you select from the list is a function that returns an Execution
, and you call it to create a new instance.
Func<Execution> createExecutionFunction = // however you randomly select one
Execution execution = createExecutionFunction();
Instantiating custom C# classes from IronPython
Assuming MyClass is in MyAssembly.dll:
import clr
clr.AddReference('MyAssembly.dll')
import MyClass
obj = MyClass("Hello, World!")
obj.Write()
How can I instantiate a class with a method (if possible) in c#?
There are many ways to do this. The most common and accepted way may be the FactoryPattern
.
Create your factory:
public static class MyClassFactory
{
public static MyClass CreateNew() {
return new MyClass();
}
public static MyClass[] CreateRange(int amount) {
var myArr = new MyClass[amount];
for (int i = 0; i < amount; i++)
{
myArr[i] = new MyClass();
}
return myArr;
}
}
Then simply call it in your code:
class Program
{
static void Main(string[] args)
{
MyClass[] myClasses = MyClassFactory.CreateRange(16);
}
}
Related Topics
Scope_Identity() Always Returning 0
Insert into SQL Db a String That Contain Special Character '
C# Invalid Attempt to Call Read When Reader Is Closed
How to Convert This C# Rijndael Encryption to PHP
C# Dllimport with C++ Boolean Function Not Returning Correctly
How to Hook into Hardware Keyboard Events at an Application Level
How Could the New Async Feature in C# 5.0 Be Implemented with Call/Cc
Can You Call a C# Dll from a C Dll
C# Call C++ Dll Passing Pointer-To-Pointer Argument
How Get List of Local Network Computers
How to Pass Strings from C# to C++ (And from C++ to C#) Using Dllimport
C# Generics Compared to C++ Templates
Parsing HTML to Get Script Variable Value
Best Way to Iterate Folders and Subfolders
How to Use HTML.Textboxfor with Input Type=Date
Capturing Count from an SQL Query
Capturing Webpage as Image in C#, Ensuring JavaScript Rendered Elements Are Visible