Skip to content

RuntimeBinderException - Cannot implicitly convert type 'Python.Runtime.PyObject' to 'System.Collections.Generic.List<string>' #451

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

Closed
tomhunter-gh opened this issue Apr 5, 2017 · 10 comments

Comments

@tomhunter-gh
Copy link

Environment

  • Pythonnet version: 2.3.0
  • Python version: 3.6 (Anaconda 32-bit)
  • Operating System: Windows 10

Details

I have the following code:

Interface1.cs

using System.Collections.Generic;

public interface Interface1
{
    string Test();

    List<string> GetList();

    List<MyType> GetListOfMyType();
}

public class MyType
{
}

Class1.cs

using System.Collections.Generic;

namespace Python.EmbeddingTest
{
    public class Class1 : Interface1
    {
        public string Test()
        {
            return "test";
        }

        public List<string> GetList()
        {
            return new List<string>() { "testing" };
        }

        public List<MyType> GetListOfMyType()
        {
            return new List<MyType>() { new MyType(), new MyType() };
        }
    }
}

Module1.py

import clr

clr.AddReference("Python.EmbeddingTest")
from Python.EmbeddingTest import *

class Class2(Class1):

    def Test(self):
        return "Test from Class2"
    
    def Method1(self):
        return "Method1"

Test

I am trying to do something like what the following test is trying to do:

[Test]
public void TestGenericListMarshalling()
{
    var scope = Py.Import("module1");
    var attr = scope.GetAttr("Class2");
    dynamic c2 = attr.Invoke();
    List<string> ls = c2.GetList();
}

Exception

However, I get the following exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException occurred
  HResult=0x80131500
  Message=Cannot implicitly convert type 'Python.Runtime.PyObject' to 'System.Collections.Generic.List<string>'
  Source=Python.EmbeddingTest
  StackTrace:
   at Python.EmbeddingTest.PyImportTest.TestGenericListMarshalling() in D:\Users\Tom\Dropbox\Algo Trading\pythonnet\src\embed_tests\pyimport.cs:line 90

Is it possible to marshall generic .NET Lists?

@den-run-ai
Copy link
Contributor

den-run-ai commented Apr 5, 2017

@tomhunter-gh can you try from the master?

pip install git+https://github.com/pythonnet/pythonnet -U --force

This should have been fixed recently:
#427

@tomhunter-gh
Copy link
Author

Hi @denfromufa

I pulled latest from master but I'm afraid I still get the problem. It looks like casting to a string[] array is successful, but the C# base class (and interface) are defined with a List<string> so I was expecting to be able to cast the dynamic back to a List<string>..

image

Were you able to reproduce the issue? What I did was I added the Interface1.cs, Class1.cs, Module.py to the Python.EmbeddingTest project. (By the way, in that project, any reason the 'fixtures' folder is not included in the project file?)

Thanks

@den-run-ai
Copy link
Contributor

den-run-ai commented Apr 6, 2017

@tomhunter-gh can you share your full project in a zip file? just paste it here to this issue.

fixtures are not included because it is python code, but could be included as a resource. we have a separate pyproj in the directory with python tests.

@tomhunter-gh
Copy link
Author

@tomhunter-gh
Copy link
Author

By the way I'm using Python 3.6 32-bit, so you may need to change settings in the Python.Runtime project file.

My test is in: pythonnet\src\embed_tests\pyimport.cs

Thanks

@den-run-ai
Copy link
Contributor

@tomhunter-gh actually that pull request which I linked above #427 leads to this issue :(

Here is the code that I commented out to pass your the test:

            /*if (value is IList && value.GetType().IsGenericType)
            {
                using (var resultlist = new PyList())
                {
                    foreach (object o in (IEnumerable)value)
                    {
                        using (var p = new PyObject(ToPython(o, o?.GetType())))
                        {
                            resultlist.Append(p);
                        }
                    }
                    Runtime.XIncref(resultlist.Handle);
                    return resultlist.Handle;
                }
            }*/

The reason is because before the list is passed back to C#, it gets converted to Python list.

So quick workaround would be to provide equivalent conversion from Python to C#: list -> List.

But this is of course a lot of conversion back and forth and maybe a performance issue.

@den-run-ai
Copy link
Contributor

This is rather hackish workaround, but passes all tests! Use at your own risk :)

pythonnet_hackish.zip

@tomhunter-gh
Copy link
Author

Thanks @denfromufa - that has fixed the issue!

Here's the change in case anyone else needs it:

image

(You also need to add a reference to Microsoft.CSharp.)

image

Thanks

@den-run-ai
Copy link
Contributor

related issue:

#514

@lostmsu lostmsu added this to the 3.0.0 milestone Sep 23, 2021
@lostmsu
Copy link
Member

lostmsu commented Sep 23, 2021

I believe this should already be fixed in 3.0, but we need a test.

lostmsu added a commit to losttech/pythonnet that referenced this issue Oct 7, 2021
@lostmsu lostmsu closed this as completed Oct 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants