Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы ОСиСП.doc
Скачиваний:
68
Добавлен:
11.05.2015
Размер:
1.78 Mб
Скачать

Распаковка-преобразование

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

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

  2. Копирование значения из экземпляра в переменную типа-значения.

В следующих операторах показаны операции по упаковке и распаковке.

int i = 123; // a value type

object o = i; // boxing

int j = (int)o; // unboxing

На следующем рисунке представлен результат выполнения предыдущих операторов.

Распаковка-преобразование:

Для успешной распаковки типов значений во время выполнения необходимо, чтобы экземпляр, который распаковывается, был ссылкой на объект, предварительно созданный с помощью упаковки экземпляра этого типа значения. Попытка распаковать null или ссылку в несовместимый тип значения вызовет InvalidCastException.

Вопрос № 8

Ссылочные типы данных. Объектная модель в среде .Net и языке c#.

Переменные ссылочных типов, называемые объектами, сохраняют ссылки на фактические данные.

Ключевые слова для объявления ссылочных типов:

  1. Class

  2. Interface

  3. Delegate

  4. Object

  5. string

Class

Классы объявляются с помощью ключевого слова class.

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

Наследование

Пример

Отсутствует

class ClassA { }

Одиночный

class DerivedClass: BaseClass { }

Отсутствует, реализует два интерфейса

class ImplClass: IFace1, IFace2 { }

Одиночное, реализует один интерфейс

class ImplDerivedClass: BaseClass, IFace1 { }

Во вложенных классах разрешены только следующие уровни доступа: protectedиprivate.

Можно объявить универсальные классы, имеющие параметры типа.

Класс может содержать объявления следующих членов.

Конструкторы

Деструкторы

Константы

Поля

Методы

Свойства

Индексаторы

Операторы

События

Делегаты

Классы

Интерфейсы

Структуры

Типы, объявленные в классе без модификатора доступа, по умолчанию являются private.

Interface

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

interface ISampleInterface

{

void SampleMethod();

}

class ImplementationClass : ISampleInterface

{

// Explicit interface member implementation:

void ISampleInterface.SampleMethod()

{

// Method implementation.

}

static void Main()

{

// Declare an interface instance.

ISampleInterface obj = new ImplementationClass();

// Call the member.

obj.SampleMethod();

}

}

Интерфейс может быть членом пространства имен или класса и содержать подписи следующих членов:

Методы

Свойства

Индексаторы

События

Интерфейс способен наследовать от одного или нескольких базовых интерфейсов.

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

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

Дополнительные сведения и примеры кода с явной реализацией интерфейса см. в разделе Явная реализация интерфейса (руководство по программированию в C#).

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

interface IPoint

{

// Property signatures:

int x {get; set;}

int y {get; set;}

}

class Point : IPoint

{

// Fields:

private int _x;

private int _y;

// Constructor:

public Point(int x, int y)

{

_x = x;

_y = y;

}

// Property implementation:

public int x

{

get {return _x;}

set {_x = value;}

}

public int y

{

get {return _y;}

set {_y = value;}

}

}

class MainClass

{

static void PrintPoint(IPoint p)

{

Console.WriteLine("x={0}, y={1}", p.x, p.y);

}

static void Main()

{

Point p = new Point(2, 3);

Console.Write("My Point: ");

PrintPoint(p);

}

}

// Output: My Point: x=2, y=3

Delegate

Объявление типа делегата аналогично подписи метода. Оно имеет возвращаемое значение и некоторое число параметров какого-либо типа:

public delegate void TestDelegate(string message);

public delegate int TestDelegate(MyType m, long num);

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

Делегаты аналогичны используемым в языке C++ указателям на функции, но являются строго типизированными и безопасными.

Делегаты являются основой событий.

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

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

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

Пример

// Declare delegate -- defines required signature:

delegate double MathAction(double num);

class DelegateTest

{

// Regular method that matches signature:

static double Double(double input)

{

return input * 2;

}

static void Main()

{

// Instantiate delegate with named method:

MathAction ma = Double;

// Invoke delegate ma:

double multByTwo = ma(4.5);

Console.WriteLine(multByTwo);

// Instantiate delegate with anonymous method:

MathAction ma2 = delegate(double input)

{

return input * input;

};

double square = ma2(5);

Console.WriteLine(square);

// Instantiate delegate with lambda expression

MathAction ma3 = s => s * s * s;

double cube = ma3(4.375);

Console.WriteLine(cube);

}

}

Object

Тип object представляет собой псевдоним для Object в платформе .NET Framework. В унифицированной системе типов C# все типы, предопределенные и пользовательские, ссылочные типы и типы значений, наследуют непосредственно или косвенно отObject. Переменным типа object можно назначать значения любых типов. Когда переменная типа значения преобразуется в объект, говорят, что она упаковывается. Когда переменная типа object преобразуется в тип значения, говорят, что она распаковывается.

Пример

В следующем примере показывается, как переменные типа object могут принимать значения любого типа данных, а также как переменные типа object могут использовать методы для Objectиз платформы .NET Framework.

class ObjectTest

{

public int i = 10;

}

class MainClass2

{

static void Main()

{

object a;

a = 1; // an example of boxing

Console.WriteLine(a);

Console.WriteLine(a.GetType());

Console.WriteLine(a.ToString());

a = new ObjectTest();

ObjectTest classRef;

classRef = (ObjectTest)a;

Console.WriteLine(classRef.i);

}

}

/* Output

1

System.Int32

1

* 10

*/

String

Тип данных string — это последовательность, содержащая ни одного или любое число знаков Юникода. В платформе.NET Framework string является псевдонимом для String.

Несмотря на то, что тип string является ссылочным типом, операторы равенства (== и !=) определены для сравнения значений объектов типа string, а не ссылок. Это упрощает проверку равенства строк. Пример.

string a = "hello";

string b = "h";

// Append to contents of 'b'

b += "ello";

Console.WriteLine(a == b);

Console.WriteLine((object)a == (object)b);

В этом примере отображается "True", а затем "False", поскольку содержимое строк одинаково, но a и b ссылаются на разные экземпляры строк.

Оператор + служит для объединения строк.

Строки являются неизменяемыми: содержимое строкового объекта невозможно изменить после создания объекта, хотя из-за синтаксиса изменения кажутся возможными. Например, при написании этого кода компилятор на самом деле создает новый строковый объект для новой последовательности знаков, а переменная b по-прежнему содержит "h".

string b = "h";

b += "ello";

Оператор [] служит для доступа только для чтения к отдельным знакам объекта string.

string str = "test";

char x = str[2]; // x = 's';

Строковые литералы имеют тип string и могут быть написаны в двух формах: в кавычках и в кавычках с @. Строковые литералы в кавычках заключены в двойные кавычки (").

"good morning" // a string literal

Строковые литералы могут содержать любые символьные литералы. Escape-последовательности также поддерживаются.

string a = "\\\u0066\n";

Эта строка содержит обратную косую черту, букву f и знак новой строки.

Примечание.

Литералы из точных сток начинаются со знака @ и заключены в двойные кавычки. Пример:

@"good morning" // a string literal

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

@"c:\Docs\Source\a.txt"

Чтобы включить знак двойной кавычки в строку в кавычках с @, следует использовать знак кавычек дважды:

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

Знак @ также можно применять для использования указанных идентификаторов (/reference), являющихся ключевыми словами C#.

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

Вопрос № 9