Перегрузка оператора в классе, который реализует интерфейс - PullRequest
0 голосов
/ 25 мая 2018

Предположим, у меня есть интерфейс IFoo и класс Foo, который реализует IFoo.Я хочу определить свою собственную логику для определения, равны ли 2 экземпляра Foo на основе содержащихся в них данных, и перегружать операторы == &! = Для простоты использования при работе с Foo.

Если у меня 2экземпляры Foo, оба хранятся как Foo, тогда это работает нормально.Однако, если у меня есть 2 экземпляра, оба хранятся как IFoo, внезапно мои перегруженные операторы больше не вызываются.Кроме того, поскольку я не могу определить оператор в своем интерфейсе IFoo, и хотя бы один из аргументов в моей перегрузке оператора Foo должен иметь тип Foo, я не вижу, как можно успешно перегрузить оператор в моем типе,Это правильно?

Кроме того, кто-нибудь может прояснить, почему это происходит?Обычно я ожидаю, что тот факт, что мои Foos хранятся как IFoos, не имеет значения при определении, какая функция равенства вызывается, поскольку по сути они все еще Foos!

Любая помощь действительно ценится

Спасибо

Редактировать: Хорошо, так как, кажется, есть некоторая путаница в том, что я имею в виду, вот пример, который, надеюсь, немного прояснит:

public interface IFoo
{
}

public class Foo : IFoo
{
    public static bool operator==(Foo left, Foo right)
    {
        ....
    }
}

Foo foo1 = new Foo();
Foo foo2 = new Foo();
bool comparison1 = foo1 == foo2    //This is successfully calling the overloaded operator

IFoo ifoo1 = foo1;
IFoo ifoo2 = foo2;
bool comparison2 = ifoo1 == ifoo2    //This isn't

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

В основном то, что сказал Алораман, но позвольте мне выразить это иначе, чтобы выяснить, становится ли это яснее.

Когда у вас есть две переменные, объявленные как IFoo, но затем вы создаете их как объекты Foo, объявление переменной определяет то, что доступнона проверку синтаксиса.Объявление переменной доступно для просмотра компилятору, но создание экземпляра, которое не происходит до выполнения, отсутствует, поэтому у компилятора нет возможности увидеть, что это действительно два объекта Foo.Поскольку IFoo не имеет и не может иметь перегруженный оператор ==, компилятор правильно видит это как ошибку.

Когда компилятор пытается выяснить, что использовать для какой-либо операции, он не может знать, что эти объекты действительно являются Fooпотому что назначение этих переменных IFoo для объектов Foo происходит во время выполнения.Компилятор не может понять, что вы действительно хотите использовать один класс, который реализует IFoo и перегружает == при сравнении этих двух переменных IFoo.

Но когда переменные определены как Foo, компилятор прекрасно знает, что при выполнениикогда они создаются, их нужно создавать как тип Foo, и он точно знает, куда идти для компиляции этого оператора ==.

По сути, компилятор, когда он пытается скомпилировать этот оператор ==, НЕ делаетпросмотрите весь другой код, чтобы увидеть, как вы создали экземпляры двух операндов.Если они определены как IFoo, это единственная информация, которую он может иметь.

0 голосов
/ 25 мая 2018

Перегрузка оператора существует только во время компиляции, после компиляции это просто вызов определенного статического метода с хорошо известным именем.

Компилятор C # распознает перегрузку оператора для Foo и заменяет a == bс Foo.op_Equality(a,b).Это означает, что после компиляции в классе Foo существует не виртуальный статический метод op_Equality.Поэтому невозможно перегрузить операторы для интерфейсов - интерфейсы не могут иметь статических методов.Более того, операторные методы не виртуальны , что означает, что реальный метод разрешается из типов переменных, а не типов значений, поэтому компилятор будет искать возможные перегрузки операторов на основе типов переменных a и b, если оба они IFoo, то он может искать только op_Equality в IFoo типе - который не может иметь его.

Вы можете предоставить пользовательскую логику только для методов, которые разрешаются на основе типов значений - это виртуальные методы, например, вы можете переопределить метод Equals для типа Foo, но это не поможетвы с IFoo a == IFoo b, который будет разрешен до Object.ReferenceEquals(a,b)

...