Могу ли я использовать явный оператор для создания производного класса? - PullRequest
2 голосов
/ 08 февраля 2011
class Base
{
}

class Derived1 : Base
{
}

class Derived2 : Base
{
    public static explicit operator Derived1(Derived2 d2)
    {
        return new Derived1();
    }
}

class Test
{
    static void Main()
    {
        Base bd2 = new Derived2();

        Derived1 d2ConvertedD1 = (Derived1)bd2; //throws InvalidCastException

    }
}

Unable to cast object of type 'ConsoleApplication1.Derived2' to type 'ConsoleApplication1.Derived1'.

Почему? Что не так с моим оператором конвертации?

Ответы [ 5 ]

10 голосов
/ 08 февраля 2011

Проблема в том, что ваше пользовательское преобразование не используется, потому что тип времени компиляции bd2 равен Base, а не Derived2. Компилятор даже не рассматривает ваше пользовательское преобразование, поэтому он просто включает в себя обычное приведение - что по очевидной причине не удается. (Я предполагаю, что вы понимаете эту ошибку, иначе вы не создали бы пользовательское преобразование для начала.)

Операторы и преобразования выбираются компилятором на основе типов операндов времени компиляции.

Хотя вы могли бы сначала привести к Derived2 или изменить объявление bd2, я лично полностью изменил бы такт и снова посмотрел на более широкую картину. Что вы пытаетесь сделать и почему? Может быть, виртуальный метод в Base имеет больше смысла, например?

5 голосов
/ 08 февраля 2011

Вы можете приводить классы только вверх и вниз по иерархии, но не поперек.

1 голос
/ 08 февраля 2011

Посмотрите на подпись вашего оператора:

public static explicit operator Derived1(Derived2 d2);

Обратите внимание, что статический . То, что вы видите, похоже на ограничение разрешения перегрузки метода.

По сути, это та же самая причина, по которой ниже выводится «Объект» вместо «Строка»:

static void WriteObject(object obj) { Console.WriteLine("Object"); }
static void WriteObject(string str) { Console.WriteLine("String"); }

object obj = "I am a string.";
WriteObject(obj);

То есть компилятору нужно выбрать перегрузку во время компиляции. В случае приведения от Base к Derived1 перегрузка с надлежащей подписью отсутствует, поэтому он пытается выполнить фактическое снижение. Объявление bd2 как Derived2, как уже упоминали другие, "исправит" это, позволив компилятору выбрать ваше пользовательское преобразование.

0 голосов
/ 08 февраля 2011

приведение к базовому классу. Если вы создаете сложную иерархию классов, подумайте о реализации интерфейсов и программировании на основе интерфейсов.

0 голосов
/ 08 февраля 2011

Класс Derived2 не наследуется от класса Derived1, поэтому это не удается.

Допустимо следующее:

Base d2ConvertedBase = (Base) bd2;

Если Derived2 должен был унаследовать от Derived1, то, что вы пытались, будет действительным.

...