Неявные / явные методы преобразования унаследованы в C #? - PullRequest
7 голосов
/ 09 июня 2009

Я не уверен, что я делаю здесь не так. У меня есть универсальный класс, который в основном является прославленным целым числом, с несколькими методами для определенного форматирования строки, а также в / из преобразования строк и int:

public class Base
{
    protected int m_value;
    ...
    // From int
    public static implicit operator Base(int Value)
    {
        return new Base(Value);
    }
    ...
    // To string
    public static explicit operator string(Base Value)
    {
        return String.Format("${0:X6}", (int)Value);
    }
}

И все работает нормально. Я могу успешно использовать неявные и явные преобразования:

Base b = 1;
Console.WriteLine((string)b);  // Outputs "$000001", as expected.

Затем я наследую от этого класса разные дочерние классы, которые включают / выключают разные именованные биты в m_value. Например:

public class Derived : Base
{

}

И тогда я не могу использовать неявные преобразования в / из int:

Derived d = 3;
// Cannot implicitly convert type 'int' to 'Derived'. An explicit conversion exists (are you missing a cast?)

Даже это дает ту же ошибку:

Derived d = (int)3;

Неявные / неявные преобразования не наследуются в производном классе? Это потребует большого количества копирования кода, если нет.

РЕАКЦИЯ Большое спасибо за быстрые ответы! Вы все заслуживаете галочки «ответ», все они очень хорошие ответы. Ключ должен думать о типах с обеих сторон знака равенства. Теперь, когда я думаю об этом, это имеет смысл.

Мне, очевидно, нужно только переписать мои преобразования "в производные". Преобразования "в Int32, String и т. Д." По-прежнему применяются.

Ответы [ 6 ]

6 голосов
/ 09 июня 2009

Причина

Derived d = (int)3;

не работает, потому что тип Derived не совсем соответствует возвращаемому значению оператора Base, что требуется для вызова этого оператора. Обратите внимание, что вы не предоставили операторов преобразования, которые содержат код new Derived(...), поэтому неудивительно, что вы не можете создавать новые Derived экземпляры таким образом.

Обратите внимание, однако, что обратное преобразование

Derived v = ...;
string s = (string)v;

будет работать нормально (как если бы оно было «унаследовано», хотя это не совсем наследование из-за ключевого слова static).

3 голосов
/ 09 июня 2009

Нет, так работать не будет. Компилятор не будет неявно понижен с базы до производной для вас. В принципе, вы не можете сделать ...

D d = new B();

Вы получите имплентации базового класса от приведения строки, потому что это сделает неявное обновление для вас.

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

public static class Ext
{
    public static D IntAsD(this int val)
    {
        return new D(val);
    }
}

Тогда вы могли бы делать то, что вы хотите с ...

D d1 = 5.IntAsD();

Конечно, он не идеален, но может соответствовать вашим потребностям.

2 голосов
/ 09 июня 2009

Перегруженные операторы (включая преобразования) наследуются, но не так, как вы ожидаете. В частности, они не магически расширены для работы с производными типами. Давайте снова посмотрим на ваш код:

Derived d = 3;

На данный момент у компилятора есть два класса для работы: System.Int32 и Derived. Так что он ищет операторы преобразования в этих классах. Он будет учитывать те, что унаследованы от производных от базы, а именно:

public static implicit operator Base(int Value);
public static explicit operator string(Base Value);

Второй не совпадает, потому что аргумент должен быть Int32. Первый действительно соответствует аргументу, но затем возвращается тип Base, а этот не соответствует. С другой стороны, вы можете написать это:

string s = (string) new Derived();

И это будет работать, потому что явный оператор в Base существует и применим (аргумент, как ожидается, будет Base, Derived наследуется от Base и поэтому соответствует типу аргумента).

Причина, по которой компилятор не может автоматически переопределять операторы преобразования в производных типах «должным образом», заключается в том, что нет общего способа сделать это.

1 голос
/ 09 июня 2009

Методы преобразования / оператора удобны, но, как отмечали другие, они не всегда будут делать то, что вы хотите. В частности, если компилятор не видит правильные типы по обе стороны от знака =, он даже не будет учитывать ваш переход / оператор. Вот почему, если вы выполните следующее, вы получите предупреждение компилятора:

object str = "hello";
if ( str == "hello" ) {
}

Кроме того, пользовательские преобразования не учитываются при использовании ключевых слов as / is.

Размышляя о реализации явного / неявного преобразования, вы должны также рассмотреть возможность реализации IConvertible и / или реализации TypeConverter. Это дает вам гораздо больше гибкости при преобразованиях типов дескрипторов базового класса.

0 голосов
/ 29 декабря 2017

Хотя вы не можете сделать это напрямую, есть несколько ярлыков, которые можно использовать для повторного использования кода.

public class Base
{
    protected int m_value;
    ...
    // From int
    public static implicit operator Base(int Value)
    {
        Base newObject = new Base();
        newObject.FromInt(Value);
        return newObject;
    }
    ...
    // To string
    public static explicit operator string(Base Value)
    {
        return String.Format("${0:X6}", (int)Value);
    }

    //Instance FromInt()
    protected void FromInt(int value)
    {
        m_value = value;
    }
}

public class Derived : Base
{
    // To string, re-use Base-ToString
    public static explicit operator string(Derived Value)
    {
        // Cast (Derived)Value to (Base)Value and use implemented (Base)toString
        return (string)(Base)Value;
    }

    // Use FromInt, which has access to instance variables
    public static implicit operator Base(int Value)
    {
        // We can't use (Base)obj = Value because it will create
        // a "new Base()" not a "new Derived()"
        Derived newObject = new Derived();
        newObject.FromInt(Value);
        return newObject;
    }
}
0 голосов
/ 09 июня 2009

Нет, это не так. Вот подсказка:

public **static** implicit operator Base(int Value)

статические методы в C # - это просто глобальные функции с доступом к закрытым членам класса. Они никогда не наследуются

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...