Почему Python.NET использует базовый метод вместо метода из производного класса? - PullRequest
0 голосов
/ 18 октября 2018

Редактировать: это будет исправлено в новой версии 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 и Transmit метод BaseClass для создания исключения NotImplementedException.

При запуске следующего кода 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.Спасибо за вашу помощь!

Редактировать: На этот вопрос нет ответа .Там сказано, что

Новый модификатор инструктирует компилятор использовать реализацию вашего дочернего класса вместо реализации родительского класса.Любой код, который не ссылается на ваш класс, но родительский класс будет использовать реализацию родительского класса.

, что явно не то, что происходит здесь.

Редактировать 2: Кажется, этопроблема с библиотекой pythonnet. Теперь проблема на github.

1 Ответ

0 голосов
/ 22 октября 2018

Разрешение метода 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;
    }
}

Примечание. Я не проводил обширные тесты, поэтому я не уверен, что это не будетсломать что-то еще.Как я уже сказал, весь код привязки метода кажется хрупким.

...