Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Неявные типы, анонимные типы и типы допускающие значение NULL

Поиск

Как уже говорилось ранее, можно неявно типизировать локальную переменную (но не члены класса) с помощью ключевого слова var. Переменная всё же получает тип во время компиляции, но тип предоставляется компилятором.

 

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

 

Обычные типы значений не могут иметь значение null. Однако можно создать типы значений, допускающие значение NULL, путем привязки? после типа. Например, int? является типом int, который также может иметь значение null. В CTS типы, допускающие значения NULL, являются экземплярами универсального типа структуры System.Nullable<T>. Типы, допускающие значение NULL, особенно полезны при передаче данных в базы данных и из них, в которых числовые значение могут быть равны NULL.

Понятие «Литералы»

Понятие «Литерал»

 

Понятие «Литерал»

 

В С# литералами называются постоянные значения, представленные в удобной для восприятия форме. Например, число 100 является литералом. Сами литералы и их назначение настолько понятны, что они применялись во всех предыдущих примерах программ без всяких пояснений. Но теперь настало время дать им формальное объяснение.

В С# литералы могут быть любого простого типа. Представление каждого литерала зависит от конкретного типа. Как пояснялось ранее, символьные литералы заключаются в одинарные кавычки. Например, 'а' и '%' являются символьными литералами.

Целочисленные литералы указываются в виде чисел без дробной части. Например,10 и -100 — это целочисленные литералы.

Для обозначения литералов с плавающей точкой требуется указывать десятичную точку и дробную часть числа. Например, 11.123 — это литерал с плавающей точкой.

Для вещественных чисел с плавающей точкой в С# допускается также использовать экспоненциальное представление.

У литералов должен быть также конкретный тип, поскольку С# является строго типизированным языком. В этой связи возникает естественный вопрос: к какому типу следует отнести числовой литерал, например 2, 12 3987 или 0.23? К счастью, для ответа на этот вопрос в С# установлен ряд простых для соблюдения правил:

  • Во-первых, у целочисленных литералов должен быть самый мелкий целочисленный тип, которым они могут быть представлены, начиная с типа int. Таким образом, у целочисленных литералов может быть один из следующих типов: int, uint, long или ulong в зависимости от значения литерала.
  • Литералы с плавающей точкой относятся к типу double.
  • Если программиста не устраивает используемый по умолчанию тип литерала, можно явно указать другой его тип с помощью суффикса.

 

Так, для указания типа long к литералу присоединяется суффикс l или L. Например, 12 — это литерал типа int, a 12L — литерал типа long. Для указания целочисленного типа без знака к литералу присоединяется суффикс u или U. Следовательно, 100 — это литерал типа int, a 100U — литерал типа uint. А для указания длинного целочисленного типа без знака к литералу присоединяется суффикс ul или UL. Например, 984375UL — это литерал типа ulong.

Кроме того, для указания типа float к литералу присоединяется суффикс f или F. Например, 10.19F — это литерал типа float. Можно даже указать тип double, присоединив к литералу суффикс d или D, хотя это излишне. Ведь, как упоминалось выше, по умолчанию литералы с плавающей точкой относятся к типу double.

И наконец, для указания типа decimal к литералу присоединяется суффикс m или М. Например, 9.95М — это десятичный литерал типа decimal.

Несмотря на то что целочисленные литералы образуют по умолчанию значения типа int, uint, long или ulong, их можно присваивать переменным типа byte, sbyte, short или ushort, при условии, что присваиваемое значение может быть представлено целевым типом.

 

Шестнадцатеричные литералы

 

В программировании иногда оказывается проще пользоваться системой счисления по основанию 16, чем по основанию 10. Система счисления по основанию 16 называется шестнадцатеричной. В ней используются числа от 0до 9, а также буквы от А до F, которыми обозначаются десятичные числа 10,11,12,13, 14 и 15. Например, десятичному числу 16 соответствует шестнадцатеричное число 10.Вследствие того что шестнадцатеричные числа применяются в программировании довольно часто, в С# разрешается указывать целочисленные литералы в шестнадцатеричном формате. Шестнадцатеричные литералы должны начинаться с символов Ох, т.е. нуля и последующей латинской буквы «икс». Ниже приведены некоторые примеры шестнадцатеричных литералов:

 

count = OxFF; // 255 в десятичной системе

incr = Ox1a; // 26 в десятичной системе

 

Управляющие последовательности символов

 

Большинство печатаемых символов достаточно заключить в одинарные кавычки, но набор в текстовом редакторе некоторых символов, например возврата каретки, вызывает особые трудности. Кроме того, ряд других символов, в том числе одинарные и двойные кавычки, имеют специальное назначение в С#, поэтому их нельзя использовать непосредственно. По этим причинам в С# предусмотрены специальные управляющие последовательности символов:

 

Управляющая последовательность Описание
\a Звуковой сигнал (звонок)
\b Возврат на одну позицию
\f Перевод страницы (переход на новую страницу)
\n Новая строка (перевод строки)
\r Возврат каретки
\t Горизонтальная табуляция
\v Вертикальная табуляция
\0 Пустой символ
\' Одинарная кавычка
\" Двойная кавычка
\\ Обратная косая черта

 

Строковые литералы

 

В С# поддерживается еще один тип литералов — строковый. Строковый литерал представляет собой набор символов, заключенных в двойные кавычки. Например, следующий фрагмент кода:

 

"Это текст"

 

Помимо обычных символов, строковый литерал может содержать одну или несколько управляющих последовательностей символов, о которых речь шла выше. Также можно указать буквальный строковый литерал. Такой литерал начинается с символа после которого следует строка в кавычках. Содержимое строки в кавычках воспринимается без изменений и может быть расширено до двух и более строк. Это означает, что в буквальный строковый литерал можно включить символы новой строки, табуляции и прочие, не прибегая к управляющим последовательностям. Единственное исключение составляют двойные кавычки «"», для указания которых необходимо использовать две двойные кавычки подряд «" "». Пример:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class Program

{

static void Main(string[] args)

{

// Используем перенос строки

Console.WriteLine("Первая строка\nВторая строка\nТретья строка\n");

// Используем вертикальную табуляцию

Console.WriteLine(" Первый столбец \v Второй столбец \v Третий столбец \n");

// Используем горизонтальную табуляцию

Console.WriteLine("1\t2\t3");

Console.WriteLine("Четыре\tПять\tШесть\n");

//Вставляем кавычки

Console.WriteLine("\"Зачем?\", - спросил он");

Console.WriteLine("Для продолжения нажмите любую клавишу... ");

Console.ReadKey();

}

}

}

/* Выведет:

* Первая строка

* Вторая строка

* Третья строка

*

* Первый столбец | Второй столбец | Третий столбец

*

* 1 2 3

* Четыре Пять Шесть

*

* "Зачем?, - спросил он

* Для продолжения нажмите любую клавишу...

*/

3.4.6. Преобразование типов данных

Преобразование типов данных

 

1. Виды преобразования типов данных

 

Поскольку в C# тип определяется статически тип во время компиляции, после объявления переменной, она не может быть объявлена вновь или использоваться для хранения значений другого типа, если этот тип не преобразуется в тип переменной. Например, невозможно преобразование из целого числа в произвольную строку. Поэтому после объявления переменной i как целочисленной, нельзя ей присвоить строку «Hello», как показано в следующем коде:

 

int i;

i = "Hello"; // Неявное преобразование типа "string" в "int" (ошибка)

 

Но иногда может быть необходимым скопировать значение в переменную или параметр метода другого типа. Например, может быть переменная, которую требуется передать методу, параметр которого имеет тип double. Или может понадобиться присвоить переменную класса переменной типа интерфейса.Операции такого вида называются преобразованиями типов. В C# можно выполнять следующие виды преобразований:

  • Неявные преобразования. Не требуется никакого специального синтаксиса, поскольку преобразование безопасно для типов и данные не теряются. Примерами могут служить преобразования от меньшего к большему целому типу, и преобразования из производных классов в базовые классы.
  • Явные преобразования (приведения). Для явных преобразований необходим оператор приведения. Приведение требуется, когда при преобразовании может быть потеряна информация, или когда преобразование может завершиться неудачей по другим причинам. К типичным примерам относится числовое преобразование в тип, который имеет меньшую точность или меньший диапазон значений, а также преобразование экземпляра базового класса в производный класс.
  • Пользовательские преобразования. Пользовательские преобразования выполняются специальными методами, которые можно определить для включения явных и неявных преобразований между пользовательскими типами, не имеющих отношения базовый класспроизводный класс.
  • Преобразования с помощью вспомогательных классов. Для преобразования между несовместимыми типами, например целые числа и объекты System.DateTime, или шестнадцатеричные строки и байтовые массивы, можно использовать класс System.BitConverter, класс System.Convert и методы Parse встроенных числовых типов, таких как Int32.Parse. Дополнительные сведения см. в разделах Практическое руководство. Преобразование массива байтов в значение типа int (Руководство по программированию на C#), Практическое руководство. Преобразование строкового значения в значение типа int (Руководство по программированию на C#) и Практическое руководство. Преобразование из шестнадцатеричных строк в числовые типы (Руководство по программированию на C#) (http://msdn.microsoft.com/ru-ru/library/bb384066.aspx, http://msdn.microsoft.com/ru-ru/library/bb397679.aspx и http://msdn.microsoft.com/ru-ru/library/bb311038.aspx).

 

2.Неявные преобразования

 

Для встроенных числовых типов неявное преобразование можно выполнить, сохраняемое значение может уместиться в переменной без обрезания или округления до ближайшего. Например, переменная типа long (8-байтное целое) может хранить любое значение, которое может хранить int (4 байта в 32-разрядном компьютере). В следующем примере компилятор неявно преобразует значение справа в тип long перед присвоением его типу bigNum.

 

int num = 2147483647;

long bigNum = num;

 

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

 

Derived d = new Derived();

Base b = d; // OK

 

3. Явные преобразования

 

Однако если преобразование не может быть выполнено без риска потери данных, для компилятора требуется, чтобы пользователь выполнил явное преобразование, которое называется приведением. Приведение является способом явно указать компилятору, что нужно сделать преобразование, и что известно, что может быть потеря данных. Для выполнения приведения заключите тип, в который производится приведение, в скобки перед преобразуемым значением или переменной. Следующая программа выполняет приведение типа double к типу int. Без приведения эта программа скомпилирована не будет:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class Program

{

static void Main(string[] args)

{

double x = 1234.7;

int a;

a = (int)x;

Console.WriteLine(a);

Console.WriteLine("Для продолжения нажмите любую клавишу... ");

Console.ReadKey();

}

}

}

/* Выведет:

* 1234

* Для продолжения нажмите любую клавишу...

*/

 

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

Giraffe g = new Giraffe();

Animal a = g;

// Явное преобразование требуется перейти к производному типу.

// Примечание: Этот код откомпилируется, но выдает исключение во время выполнения,

// если с правой стороны объекта на самом деле не "жираф".

Giraffe g2 = (Giraffe)a;

 

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

 

Дополнительные сведения

 

В программировании нередко значения переменных одного типа присваиваются переменным другого типа. Например, в приведённом ниже фрагменте кода целое значение типа int присваивается переменной с плавающей точкой типа float:

int i;

float f;

i = 10;

f = i; // Присвоить целое значение переменной типа float

 

Если в одной операции присваивания смешиваются совместимые типы данных, то значение в правой части оператора присваивания автоматически преобразуется в тип, указанный в левой его части. Поэтому в приведенном выше фрагменте кода значение переменной i сначала преобразуется в тип float, а затем присваивается переменной f. Но вследствие строгого контроля типов далеко не все типы данных в С# оказываются полностью совместимыми, а следовательно, не все преобразования типов разрешены в неявном виде. Например, типы bool и int несовместимы. Правда, преобразование несовместимых типов все-таки может быть осуществлено путём приведения. Приведение типов, по существу, означает явное их преобразование.

4. Автоматическое преобразование типов

 

Когда данные одного типа присваиваются переменной другого типа, неявное преобразование типов происходит автоматически при следующих условиях:

  • оба типа совместимы;
  • диапазон представления чисел целевого типа шире, чем у исходного типа.

 

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

Числовые типы, как целочисленные, так и с плавающей точкой, вполне совместимы друг с другом для выполнения расширяющих преобразований. Рассмотрим пример:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace LC_Console

{

class Program

{

static void Main(string[] args)

{

short num1, num2;

num1 = 10;

num2 = 15;

Console.WriteLine("{0} + {1} = {2}",num1, num2, Sum(num1, num2));

Console.WriteLine("Для продолжения нажмите любую клавишу... ");

Console.ReadKey();

}

 

static int Sum(int x, int y)

{

return x + y;

}

}

}

/* Выведет:

* 10 + 15 = 25

* Для продолжения нажмите любую клавишу...

*/

 

Обратим внимание на то, что метод Sum ожидает поступления двух параметров типа int. Тем не менее, в методе Main ему на самом деле передаются две переменных типа short. Хотя это может показаться несоответствием типов, программа будет компилироваться и выполняться без ошибок и возвращать в результате, как и ожидалось, значение 25.

Причина, по которой компилятор будет считать данный код синтаксически корректным, связана с тем, что потеря данных здесь невозможна. Поскольку максимальное значение (32767), которое может содержать тип short, вполне вписывается в рамки диапазона типа int (максимальное значение которого составляет 2147483647), компилятор будет неявным образом расширять каждую переменную типа short до типа int. Формально термин «расширение» применяется для обозначения неявного восходящего приведения (upward cast), которое не приводит к потере данных.



Поделиться:


Последнее изменение этой страницы: 2016-08-15; просмотров: 538; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 13.58.61.176 (0.01 с.)