17

I want to pass a list of strings from IronPython 2.6 for .NET 2.0 to a C# program (I'm using .NET 2.0 because I'm working with an api that runs off of DLLs built on 2.0). But I'm not sure how to cast it as it comes back from the ScriptEngine.

namespace test1
{
    class Program
    {
        static void Main(string[] args)
        {
            ScriptEngine engine = Python.CreateEngine();
            ScriptSource source = engine.CreateScriptSourceFromFile("C:\\File\\Path\\To\\my\\script.py");
            ScriptScope scope = engine.CreateScope();

            ObjectOperations op = engine.Operations;

            source.Execute(scope); // class object created
            object classObject = scope.GetVariable("MyClass"); // get the class object
            object instance = op.Invoke(classObject); // create the instance
            object method = op.GetMember(instance, "myMethod"); // get a method
            List<string> result = (List<string>)op.Invoke(method); // call the method and get result
            Console.WriteLine(result.ToString());
            Console.Read();
        }
    }
}

my python code has a class with a method that returns a python list of strings:

class MyClass(object):
    def myMethod(self):
        return ['a','list','of','strings']

I get this error:

Unable to cast object of type 'IronPython.Runtime.List' to type 'System.Collections.Generic.List`1[System.String]'.
2
  • Have you tried casting the result to IronPython.Runtime.List? Commented Mar 6, 2011 at 9:25
  • no, because it already is that type and I want a System.Collections.Generic.List that I can continue to work with in C# Commented Mar 6, 2011 at 9:33

2 Answers 2

19

IronPython.Runtime.List implements the following interfaces:

IList, ICollection, IList<object>, ICollection<object>, IEnumerable<object>, IEnumerable

so you can cast to one of this types an then turn into a List<string>.

List<string> result = ((IList<object>)op.Invoke(method)).Cast<string>().ToList();

BTW, maybe you are aware of it, but you can also use .NET types in IronPython e.g.:

from System.Collections.Generic import *

class MyClass(object):
    def myMethod(self):
        return List[str](['a','list','of','strings'])

here myMethod returns directly a List<string>


EDIT:

Given that you're using .net 2.0 (so no LINQ) you have two options (IMO):

1. Cast to IList<object> and use it:

IList<object> result = (IList<object>)op.Invoke(method);

PROs: no loop required, you will use the same object instance returned by the python script.
CONs: no type safety (you will be like in python, so you can add also a non-string to the list)

2. Convert to a List<string>/IList<string> :

IList<object> originalResult = (IList<object>)op.Invoke(method);
List<string> typeSafeResult = new List<string>();
foreach(object element in originalResult)
{
    typeSafeResult.Add((string)element);
}

PROs: type safe list (you can add only strings).
CONs: it requires a loop, and the converted list is a new instance (not the same returned by the script)

Sign up to request clarification or add additional context in comments.

8 Comments

your suggestion makes sense, but when I try casting from IList, I get this error: 'System.Collections.Generic.IList<object>' does not contain a definition for 'Cast' I've probably missed something basic.
In response to your suggestion about using .NET types, I was hoping that there were some simple casts for basic python types, such as lists, dictionaries, and tuples, that I wouldn't have to replace with .net types in my python script (it is supposed to be built on .net after all). maybe there is a list of default casts for basic ironpython types somewhere
@BenjaminGolder: do you have using System.Linq; among the .cs header lines ? (you're using .net 3.5 I hope...)
@digEmAll: no should I?, and I'm actually using 2.0, because I'm using an api that works from 2.0 dlls. Sorry if I should already know these things. I'm pretty new to .NET
@BenjaminGolder: as I said, a python list is mapped as a IList<object>, so if you want to manipulate the same object instance returned from python you must cast to that. Otherwise you can turn it into a List<string> (using loops or LINQ Cast<>) but of course this means to create another instance.
|
2

You can use IList on the C# side and IronPython will automatically wrap the List object in a wrapper which does conversions to/from string when accessing the list.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.