2010-09-28 5 views
7

Пример может быть:В чем причина использования неявных/явных преобразований вместо конструкторов?

XNamespace ns = "my namespace" 

Почему не ?:

XNamespace ns = new XNamespace ("my namespace") 

То, что идея использования неявного/явного convertions вместо конструкторов? Удобство?

Есть ли руководство для этого?

ответ

9

Удобство?

Больше или меньше, да. Рассмотрим случай, когда у вас есть числовой объект (скажем, Complex), на котором вы выполняете вычисления. Очевидно, что код записи, такой как:

Complex result = c1 * new Complex(2) + new Complex(32); 

очень раздражает и трудно читается. Здесь подразумеваются неявные преобразования (альтернативой может быть перегрузка операторов в этом примере, но это приведет к множеству подобных перегрузок).

Есть ли руководство для этого?

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

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

В VB, неявное преобразование называется «Widening» (в отличие от Narrowing, который explicit), и это описывает его так: никакая информация не теряется в процессе преобразования.

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

Рассмотрите мой пример Complex. Мы можем захотеть кэшировать значения для часто используемых комплексных номеров:

Class Complex { 
    // Rest of implementation. 

    private static Complex[] cache = new[] { 
     new Complex(-1), new Complex(0), new Complex(1) }; 

    public implicit operator Complex(int value) { 
     if (value >= -1 && value <= 1) 
      return cache[value]; 
     else 
      return new Complex(value); 
    } 
} 

Конечно, вопрос о том, является ли эта микро-оптимизация эффективной, является еще одним вопросом.

+0

Спасибо, как бы вы сделали это для перегрузок операторов, которые помогли бы сложному типу? Вы должны иметь возможность редактировать тип int, правильно? –

+0

@Joan: Нет, поскольку вы можете реализовать операторов в обоих направлениях: * от * вашего пользовательского типа и * до * вашего настраиваемого типа. В моем примере просто «Complex» реализует оператор 'implicit operator Complex (int value)'. –

+0

Спасибо, я понял. –

3

Использование неявных/явных преобразований - это проблема удобства и одна из многих рекомендаций по программированию предполагает, что вы избегаете явных методов ConvertToXXX.

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

  • Просмотр тот же объект с помощью другого типа/интерфейса в иерархии объекта
  • Coverting объекта нового типа вообще

К сожалению, C# уже делает последние в других областях (с примитивами и боксом).

1

Лично я использую преобразование, когда я знаю, что ки могут быть преобразованы в статический член класса (как говорят color = "red" подразумеваю color = Colors.Red)

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

2

Если два класса должны быть конвертированы друг в друга, но они не разделяют интерфейс базового класса, который позволяет это поведение автоматически, вы должны использовать преобразования. Неявные преобразования должны быть никогда имеют возможность потери данных; они часто считаются «расширяющимися» преобразованиями. Например, преобразование int в long является расширяющимся преобразованием, и нет никакой проблемы, присущей неявному преобразованию. Явные преобразования могут включать возможность потери данных; a long может быть конвертирован или не может быть конвертирован в int, в зависимости от его стоимости.

Один трюк, который я использовал с неявными преобразованиями, заключается в преобразовании классов в разных пространствах имен друг к другу, когда у меня не было другого разумного варианта. Например, одна служба WCF возвращает объект AuthenticationToken, который мне нужно передать в службу WCF в другом пространстве имен. Оба имеют этот объект AuthenticationToken, и постоянное преобразование было бы болью. Мое решение включало использование public static implicit operator в частичном классе, чтобы добавить функциональные возможности для преобразования в каждый способ.

+0

Понятие о том, что язык «неявных преобразований не должен вызывать потери данных» популярен, но я считаю, что лучшим понятием будет «* туда-обратно * неявные преобразования не должны вызывать потерю данных». Если «SimpleType» представляет «ComplicatedType», где «сложные» свойства соответствуют значениям по умолчанию, расширение конверсий должно разрешаться только с «SimpleType» до «ComplicatedType», но если оно представляет «ComplicatedType», где значения сложных свойств неизвестны , неявное преобразование должно, во всяком случае, допускаться только по-другому. – supercat

5

Одна из причин использования неявного преобразования с такими простыми типами, как XName, является, я считаю, удобством при вызове методов.

Например, вы можете написать

var info = root.Elements ("user").Element ("info").Value; 

Простота в извлечении данных является то, что LINQ это все о, и если бы мы должны были написать

var info = root.Elements (new XName ("user")).Element (new XName ("info")).Value; 

даже для простейших запросов, было бы LINQ быть полностью стоит ли это для сложных?

Еще одна важная проблема заключается в том, что XNames распылены. См MSDN:

объекты XName гарантированно будут распылены; то есть , если два объекта XName имеют точно такое же пространство имен и точно такое же локальное имя, они будут совместно использовать один и тот же экземпляр. Для этой цели также предусмотрены операторы равенства и сравнения.

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

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

Смежные вопросы