C #: объединить DllImport с наследованием? - PullRequest
2 голосов
/ 19 октября 2011

При попытке портировать некоторый код с Java на c # возникают некоторые проблемы.

Сначала немного объяснения ключевой концепции Java-кода: Ключевой концепцией существующего кода является класс, импортирующий / использующий методы во внешней библиотеке. Этот класс реализует интерфейс, который объявляет большинство методов из внешней библиотеки. Преимущество заключается в возможности создавать экземпляры типа

Interface1 instance = new classImplementingInterface1 ();

Я пытаюсь портировать код, который реализует интерфейс и импортирует методы из внешней библиотеки. На самом деле мне пришлось перевести этот интерфейс в абстрактный класс, потому что интерфейс Java использует поля, содержащие предопределенные значения, которые не поддерживаются в интерфейсах .NET.

Это может быть моей отправной точкой:

public abstract class abstractClassA
{
    public abstract int abstractMethodA(int parameter);
}

public class usualClass : abstractClassA
{
    [DllImort("ExternalLib.dll")]
    public static extern abstractMethodA(int parameter);
}

Абстрактный класс используется для возможности создания экземпляров из классов, реализующих этот абстрактный класс, просто набирая

abstractClassA instance = new usualClass();

Хорошо, это то, что я хочу сделать, но я понял, что это не сработает, пока я наследую абстрактный класс, мне придется использовать оператор override для методов, которые я хочу реализовать, например

public class usualClass : abstractClassA
{
    public extern override abstractMethodA(int parameter);
}

Это не будет работать в сочетании с оператором DllImport, потому что он говорит мне, что методы, использующие этот оператор, должны объявлять как: extern, так и static. Добавление ключевого слова override для реализации абстрактного класса невозможно, поскольку статический член не может быть объявлен как override. Итак, я думаю, что я пойман в ловушку как: /

Но на самом деле я хочу создать класс с именем точки входа из внешней библиотеки. Но я хочу, чтобы этот класс реализовал интерфейсный / абстрактный класс, чтобы иметь возможность создавать экземпляры классов, реализующих этот интерфейсный / абстрактный класс, просто набрав

abstractClassA instance = new usualClass();

Я также попробовал это с использованием интерфейса (но без раздражающих статических предопределенных полей) и обнаружил, что реализация интерфейса не работает в сочетании с оператором DllImport, компилятор говорит, что названный метод является статическим и поэтому не может реализовать метод интерфейса. Это действительно имеет смысл, но не является подходящим решением моей проблемы.

Есть ли у вас опыт с этим или еще идеи?

Ответы [ 2 ]

5 голосов
/ 19 октября 2011

Как говорит C # компилятор, метод ДОЛЖЕН быть static extern. К счастью, DllImport имеет свойство EntryPoint, которое позволяет вам использовать другое имя в C # (таким образом избегая конфликтов имен). Например:

public abstract class AbstractClassA
{
    public abstract int AbstractMethodA(int parameter);
}

public class UsualClass : AbstractClassA
{
    [DllImport("ExternalLib.dll", EntryPoint = "abstractMethodA")]
    static extern int AbstractMethodAImport(int parameter);
    public override int AbstractMethodA(int parameter)
    {
        return AbstractMethodAImport(parameter);
    }
}

Тем не менее, ваш код не соответствует передовым практикам ( дополнительная любимая мозоль, да, именно так вы называете вещи в Java - но когда в Риме будьте римлянином, пожалуйста, ознакомьтесь с соглашениями об именах C # ) , Вы должны действительно реализовать это следующим образом:

public abstract class AbstractClassA
{
    public abstract int AbstractMethodA(int parameter);
}

public class UsualClass : AbstractClassA
{
    public override int AbstractMethodA(int parameter)
    {
        return NativeMethods.AbstractMethodA(parameter);
    }
}

[SuppressUnmanagedCodeSecurity]
internal class NativeMethods
{
    [DllImport("ExternalLib.dll", EntryPoint = "abstractMethodA")]
    public static extern int AbstractMethodA(int parameter);
}

Всегда держите свои экстерьеры в одном классе, который вы должны назвать NativeMethods.

2 голосов
/ 19 октября 2011

Вам просто нужно добавить дополнительный слой косвенности.Вы должны переопределить abstractMethodA с помощью метода C #, который в свою очередь вызывает внешний метод.

public abstract class abstractClassA
{
    public abstract int abstractMethodA(int parameter);
}

public class usualClass : abstractClassA
{
    [DllImort("ExternalLib.dll", EntryPoint="TheFunctionName")]
    private static extern abstractMethodAextern(int parameter);

    public override int abstractMethodA(int parameter)
    {
        return abstractMethodAextern(parameter);
    }
}
...