I'm just learning about Lua and trying to integrate it with C# and mono (on Linux). After some looking around, I found AluminumLua as a wrapper to do so.
I've successfully being able to call from lua to C#, but I can't see the way to call from C# to lua:
lua (test.lua):
HelloWorld()
function print_test()
print("hi")
return 1
end
C#
var context = new LuaContext ();
context.AddBasicLibrary ();
context.AddIoLibrary ();
context.SetGlobal ("HelloWorld", LuaObject.FromDelegate(new Action(HelloWorld)));
var parser = new LuaParser (context, "test.lua");
parser.Parse ();
...
public static void HelloWorld() {
Console.Write("HelloWorld");
}
That's cool, but... How can I call the function "print_test", get its output result from C#?
From looking at the source, LuaContext has a Get method which returns a LuaObject. After you have a reference to that LuaObject you can try to turn it into a LuaFunction using AsFunction and IsFunction.
Something along the lines of this should work:
// ...
var print_test = context.Get("print_test");
if (print_test.IsFunction)
{
print_test.AsFunction()(null);
}
else
{
Console.Write("print_test not a lua function!");
}
// ...
Related
I want to call a python function from C# code. To do that, I used Python for .NET to call function as shown in the following lines of code
using System;
using Python.Runtime;
public class Test{
public static void Main(){
using(Py.GIL()){
dynamic lb = Py.Import("lb");
dynamic result = lb.analyze("SomeValue");
Console.WriteLine(result);
}
}
}
The python function is something like this:
def analyze(source, printout = False, raw = True):
# removed for bravity
So the question is, how can I set "raw" to False when I call the analyze function from C# code. I tried the following but it didn't work.
1. dynamic result = lb.analyze("SomeSource", raw : false); // No result
2. dynamic result = lb.analyze("SomeSource", #"raw = False"); // No result
I know it is easy to do by doing this:
dynamic result = lb.analyze("SomeSource", False, False);
But what if there is more than six or seven named parameter, it would not be great to insert it all manually and change the one I wanted. For example, the python library that I am using have 12 named parameter with default value including two more parameters with no default value.
UPDATED
I also tried:
3. dynamic result = lb.analyze("SomeSource", raw = false); // C# compilation error
To apply keyword arguments use:
lb.analyze("SomeSource", Py.kw("raw", false));
See readme.
Another approach is using C# keyword argument syntax that was recently added to pythonnet:
lb.analyze("SomeSource", raw: false);
Since I am using one function to call python scripts I have used a Listto hold the parameter values. I am also passing in a class name and function name since my python scripts contain multiple classes with multiple functions. I don't use the 'self' parameter in any of my classes, so they are static functions. I am providing a snippet of my code to help you and anyone else out that is using python in .net. I personally use it for communciation with USB.
Here is an example of one of my callers. Ignore the function name but look at how it's calls the ExecuteScript and passing int he parameterset. Notice the list is of type object, incase your paramters are a mix of string/int/bool/objects etc.
public string SendCommand(string comport, string command)
{
try
{
List<object> parameterSet = new() { comport, command };
string result = _pythonService.ExecuteScript<string>("usb", "usb", "sendCommand", parameterSet);
return result;
}
catch (Exception)
{
throw;
}
}
Here is a function that executes the class function
public dynamic? ExecuteScript<T>(string scriptFile, string className, string functionName, List<object> paramset)
{
T? result = default;
try
{
// Location of all the python scripts in the project. lets get the python file we are specifying in the function param
string file = $"{Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)}\\PythonScripts\\{scriptFile}.py";
// This is initalized in the program.cs, but just want to make sure it's initialized in case something happens
if (!PythonEngine.IsInitialized)
{
PythonEngine.Initialize();
Py.GIL();
}
using (var scope = Py.CreateScope())
{
PyObject? pythonReturn; // Our returned PythonObject from the python function call
string code = File.ReadAllText(file); // Get the python file as raw text
var scriptCompiled = PythonEngine.Compile(code, file); // Compile the code/file
scope.Execute(scriptCompiled); // Execute the compiled python so we can start calling it.
PyObject pythonClass = scope.Get(className); // Lets get an instance of the class in python
// Add parameters to the function?
if (paramset != null && paramset.Count > 0)
{
PyObject[] pyParams = new PyObject[paramset.Count]; // This is an array of python parameters passed into a function
// Loop through our incoming c# list of parameters and create PythonObject array .
for (int i = 0; i < paramset.Count; i++)
{
pyParams[i] = paramset[i].ToPython();
}
pythonReturn = pythonClass.InvokeMethod(functionName, pyParams); // Call the function on the class with parameters
}
else // We aren't using parameters here
pythonReturn = pythonClass.InvokeMethod(functionName); // Call the function on the class
// Lets convert our returned pythonObject to that of the object type (C#)
object? netObject = pythonReturn.AsManagedObject(typeof(object));
// A special case of when we want a list back. We will convert the object to the specific type in the caller function
if (typeof(T) == typeof(IList<object>))
{
object[] something = pythonReturn.As<object[]>();
return something;
}
// Convert the c# object to that of what we expect to be returned,. string/int/bool/class
if (netObject != null)
result = (T)netObject; // convert the returned string to managed string object
}
return result;
}
catch (Exception)
{
// Handle your exceptions here
throw;
}
}
If you don't care about the entire function and just want the quick snippet of adding the params:
// Add parameters to the function?
if (paramset != null && paramset.Count > 0)
{
PyObject[] pyParams = new PyObject[paramset.Count]; // This is an array of python parameters passed into a function
// Loop through our incoming c# list of parameters and create PythonObject array .
for (int i = 0; i < paramset.Count; i++)
{
pyParams[i] = paramset[i].ToPython();
}
pythonReturn = pythonClass.InvokeMethod(functionName, pyParams); // Call the function on the class with parameters
}
else // We aren't using parameters here
pythonReturn = pythonClass.InvokeMethod(functionName); // Call the function on the class
I have some code written in Matlab however I wish to call this code from a C# console application.
I do not require any data to be returned from Matlab to my app (although if easy would be nice to see).
There appears to be a few options however not sure which is best. Speed is not important as this will be an automated task.
MATLAB has a .Net interface that's well-documented. What you need to do is covered in the Call MATLAB Function from C# Client article.
For a simple MATLAB function, say:
function [x,y] = myfunc(a,b,c)
x = a + b;
y = sprintf('Hello %s',c);
..it boils down to creating an MLApp and invoking the Feval method:
class Program
{
static void Main(string[] args)
{
// Create the MATLAB instance
MLApp.MLApp matlab = new MLApp.MLApp();
// Change to the directory where the function is located
matlab.Execute(#"cd c:\temp\example");
// Define the output
object result = null;
// Call the MATLAB function myfunc
matlab.Feval("myfunc", 2, out result, 3.14, 42.0, "world");
// Display result
object[] res = result as object[];
Console.WriteLine(res[0]);
Console.WriteLine(res[1]);
Console.ReadLine();
}
}
I have this Js functions :
function Add (a, b)
{ return a+b;}
function Substract (a, b)
{ return a-b;}
I know (heard) that I can activate those functions on c# code using the dynamic keyword.
Can I get a help ( or beginning of help) to the solution by simple sample ?
edit
If I have a webBrowser ( winform) - which can help me. ( sorry to add this now).
You need a javascript interpreter if you want to execute javascript code. The C#s dynamic keyword is pretty useless in this aspect. You may take a look at Javascript .NET or Jint if you are trying to execute those functions in .NET code.
Here's an example with Jint:
using System;
using Jint;
class Program
{
static void Main()
{
var script = #"
function Add(a, b) {
return a + b;
}
function Substract(a, b) {
return a - b;
}
return Add(a, b);
";
var result = new JintEngine()
.SetParameter("a", 3)
.SetParameter("b", 5)
.Run(script);
Console.WriteLine("result: {0}", result);
}
}
Remark: what you have is not valid javascript. The var keyword cannot be used before function parameters. So you probably should start by fixing your code.
I am writing a scripting language, i've done the lexer and parser and i want to dynamically execute in the memory.
Lets say i have something like
function Hello(World)
{
Print(world);
}
var world = "World";
var boolean = true;
if(boolean == true)
{
Print("True is True");
}
else
{
Print("False is True");
}
Hello(world);
what would be the best way to execute this snippet i'ved tried
1) OpCode Il Generation (i couldn't get if statement to work or anything other than Print function)
2) RunSharp, i cannot do the functions cause the way i can do it i have no idea how.
If anyone could point me to the right direction!
Alittle Code will help
Link to resource (not something like IronPython) would be also good
your script language like JavaScript,if it dynamic compile in memory.
example:
//csc sample.cs -r:Microsoft.JScript.dll
using System;
using System.CodeDom.Compiler;
using Microsoft.JScript;
class Sample {
static public void Main(){
string[] source = new string[] {
#"import System;
class JsProgram {
function Print(mes){
Console.WriteLine(mes);
}
function Hello(world){
Print(world);
}
function proc(){
var world = ""World"";
var bool = true;
if(bool == true){
Print(""True is True"");
}
else{
Print(""False is True"");
}
Hello(world);
}
}"
};
var compiler = new JScriptCodeProvider();
var opt = new CompilerParameters();
opt.ReferencedAssemblies.Add("System.dll");
opt.GenerateExecutable = false;
opt.GenerateInMemory = true;
var result = compiler.CompileAssemblyFromSource(opt, source);
if(result.Errors.Count > 0){
Console.WriteLine("Compile Error");
return;
}
var js = result.CompiledAssembly;
dynamic jsProg = js.CreateInstance("JsProgram");
jsProg.proc();
/*
True is True
World
*/
}
}
generate c# source and compile it :-)
http://support.microsoft.com/kb/304655
If I understand you right, you want to compile and run the code on runtime? then you could try http://www.csscript.net/index.html , its an example on the same page linked.
In my WinForms application I need to call javascript function from my WebBrowser control. I used Document.InvokeScript and it works perfect with functions alone e.g
Document.InvokeScript("function").
But when i want to call javascript object method e.g.
Document.InvokeScript("obj.method")
it doesn't work. Is there a way to make it work? Or different solution to this problem? Without changing anything in the javascript code!
Thanks in advance :)
The example in the documentation does NOT include the parenthesis.
private void InvokeScript()
{
if (webBrowser1.Document != null)
{
HtmlDocument doc = webBrowser1.Document;
String str = doc.InvokeScript("test").ToString() ;
Object jscriptObj = doc.InvokeScript("testJScriptObject");
Object domOb = doc.InvokeScript("testElement");
}
}
Try
Document.InvokeMethod("obj.method");
Note that you can pass arguments if you use HtmlDocument.InvokeScript Method (String, Object[]).
Edit
Looks like you aren't the only one with this issue: HtmlDocument.InvokeScript - Calling a method of an object . You can make a "Proxy function" like the poster of that link suggests. Basically you have a function that invokes your object's function. It's not an ideal solution, but it'll definitely work. I'll continue looking to see if this is possible.
Another post on same issue: Using WebBrowser.Document.InvokeScript() to mess around with foreign JavaScript . Interesting solution proposed by C. Groß on CodeProject:
private string sendJS(string JScript) {
object[] args = {JScript};
return webBrowser1.Document.InvokeScript("eval",args).ToString();
}
You could make that an extension method on HtmlDocument and call that to run your function, only using this new function you WOULD include parenthesis, arguments, the whole nine yards in the string you pass in (since it is just passed along to an eval).
Looks like HtmlDocument does not have support for calling methods on existing objects. Only global functions. :(
Unfortunately you can't call object methods out of the box using WebBrowser.Document.InvokeScript.
The solution is to provide a global function on the JavaScript side which can redirect your call. In the most simplistic form this would look like:
function invoke(method, args) {
// The root context is assumed to be the window object. The last part of the method parameter is the actual function name.
var context = window;
var namespace = method.split('.');
var func = namespace.pop();
// Resolve the context
for (var i = 0; i < namespace.length; i++) {
context = context[namespace[i]];
}
// Invoke the target function.
result = context[func].apply(context, args);
}
In your .NET code you would use this as follows:
var parameters = new object[] { "obj.method", yourArgument };
var resultJson = WebBrowser.Document.InvokeScript("invoke", parameters);
As you mention that you cannot change anything to your existing JavaScript code, you'll have to inject the above JavaScript method in some how. Fortunately the WebBrowser control can also do for you by calling the eval() method:
WebBrowser.Document.InvokeScript("eval", javaScriptString);
For a more robust and complete implementation see the WebBrowser tools I wrote and the article explaining the ScriptingBridge which specifically aims to solve the problem you describe.
webBrowser.Document.InvokeScript("execScript", new object[] { "this.alert(123)", "JavaScript" })
for you supposed to be like this
webBrowser.Document.InvokeScript("execScript", new object[] { "obj.method()", "JavaScript" })