首页 > 解决方案 > 为什么 Python.NET 使用基方法而不是派生类中的方法?

问题描述

编辑:这将在新版本的 pythonnet 中修复(当合并拉取请求时)。

我对 Python.NET 继承有疑问。我有一个包含以下代码的 DLL:

using System;

namespace InheritanceTest
{
    public class BaseClass
    {
        public bool Transmit()
        {
            throw new NotImplementedException();
        }
    }

    public class InheritedClass: BaseClass
    {
        public new bool Transmit()
        {
            Console.WriteLine("Success!");
            return true;
        }
    }
}

我希望调用Transmit一个实例的方法InheritedClass来写入控制台并返回 true,以及抛出 NotImplementedException的Transmit方法。BaseClass

运行以下 python 代码时:

## setup
import clr
import os

clr.AddReference(os.getcwd() + '\\InheritanceTest.dll')
import InheritanceTest

## method test

base_class = InheritanceTest.BaseClass()
base_class.Transmit() # throws a NotImplementedException as expected

inherited_class = InheritanceTest.InheritedClass()
inherited_class.Transmit() # still throws a NotImplementedException, although it should call InheritedClass.Transmit

我正在使用 pythonnet 版本 2.3.0 和 .NET Framework 4.6.1。谢谢你的帮助!

编辑:这个问题没有回答这个问题。据说那里

new 修饰符指示编译器使用您的子类实现而不是父类实现。任何不引用您的类但父类的代码都将使用父类实现。

这显然不是这里发生的事情。

编辑 2:这似乎是 pythonnet 库的问题。这个问题现在在 github 上。

标签: c#python.netooppython.net

解决方案


恕我直言,pythonnet方法分辨率(Bind在文件中找到的方法methodbinder.cs)可以改进很多。无论如何,这种方法目前并不真正关心类型层次结构。

一种简单的解决方案是更改MethodSorter类,以便在对方法进行排序以确定调用将选择哪个方法时优先使用派生类Bind

前:

internal class MethodSorter : IComparer
{
    int IComparer.Compare(object m1, object m2)
    {
        int p1 = MethodBinder.GetPrecedence((MethodBase)m1);
        int p2 = MethodBinder.GetPrecedence((MethodBase)m2);
        if (p1 < p2)
        {
            return -1;
        }
        if (p1 > p2)
        {
            return 1;
        }
        return 0;
    }
}

后:

internal class MethodSorter : IComparer
{
    int IComparer.Compare(object m1, object m2)
    {
        var me1 = (MethodBase)m1;
        var me2 = (MethodBase)m2;
        if (me1.DeclaringType != me2.DeclaringType)
        {
            // m2's type derives from m1's type, favor m2
            if (me1.DeclaringType.IsAssignableFrom(me2.DeclaringType))
                return 1;

            // m1's type derives from m2's type, favor m1
            if (me2.DeclaringType.IsAssignableFrom(me1.DeclaringType))
                return -1;
        }

        int p1 = MethodBinder.GetPrecedence((MethodBase)m1);
        int p2 = MethodBinder.GetPrecedence((MethodBase)m2);
        if (p1 < p2)
        {
            return -1;
        }
        if (p1 > p2)
        {
            return 1;
        }
        return 0;
    }
}

注意我没有进行广泛的测试,所以我不确定这不会破坏其他东西。正如我所说,整个方法绑定代码似乎很脆弱。


推荐阅读