Skip to content

Python elemental types not converted automatically when C# type is "object". #2220

@sherryyshi

Description

@sherryyshi

Environment

  • Pythonnet version: 3.0.1
  • Python version: 3.9
  • Operating System: Windows
  • .NET Runtime: netcoreapp3.1

Details

According to https://pythonnet.github.io/pythonnet/python.html#type-conversion, most elemental Python types (string, int, long, etc.) convert automatically to compatible managed equivalents (String, Int32, etc.) and vice-versa. However, when the type on the C# side is object this does not seem to happen.

Here is a sample to demonstrate what I mean:

using Newtonsoft.Json;

namespace MyClass
{
    public record MyClass
    {
        public MyClass(int x)
        {
            X = x;
        }
        public object X { get; set; }

        public string ToJson() => JsonConvert.SerializeObject(this);

        public string GetType() => X.GetType().Name;
    }
}
from MyClass import MyClass

x = MyClass(1)
print(x.GetType())
print(x.ToJson())

This works; the output is:

Int32
{"X":1}

However, if I change public MyClass(int x) to public MyClass(object x) in the C# code:

using Newtonsoft.Json;

namespace MyClass
{
    public record MyClass
    {
        public MyClass(object x)
        {
            X = x;
        }
        public object X { get; set; }

        public string ToJson() => JsonConvert.SerializeObject(this);

        public string GetType() => X.GetType().Name;
    }
}

This no longer works as expected - type is PyInt and json serialization throws an error:

PyInt
Traceback (most recent call last):
  File "C:\repos\test\LongRunningTask\python\test.py", line 15, in <module>
    print(x.ToJson())
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected with type 'Python.Runtime.PyObject'. Path 'X'.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value)
   at MyClass.MyClass.ToJson() in C:\repos\test\LongRunningTask\MyClass\MyClass.cs:line 13
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

Is this behavior expected? If so, that would be unfortunate for me since I have code in C# that does runtime type checking (if (x is Int32) etc.) and JSON serialization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions