Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Questions

.pdf
Скачиваний:
9
Добавлен:
11.03.2016
Размер:
1.14 Mб
Скачать

1.Типы данных.

1.Изучите, скомпилируйте и запустите файл types.cs и объясните работу примера в контексте темы типов-значений (value-types) и типов-ссылок (reference types).

using System;

class types

{

static public void Main(string[] args)

{

int i = 10;

string s = "Hello, world";

Console.WriteLine("Before, i = " + i);

ModifyInt(i);

Console.WriteLine("After, i = " + i);

Console.WriteLine("Before, s = " + s); ModifyString(s); Console.WriteLine("After, s = " + s);

}

static void ModifyInt(int i)

{

i = 99;

}

static void ModifyString(string s)

{

s = "Hello, I've been modified.";

}

}

- Чему равно значение переменой i до вызова функции ModifyInt? После вызова? Почему?

Значение переменной i до и после вызова функции ModifyInt составляет «10». Область видимости локальной переменной i, определенной в методе Main, ограничивается телом этого метода,

поскольку локальная переменная находится в области видимости до тех пор, пока закрывающая фигурная скобка не укажет на конец блока операторов или (в нашем случае) метода, в котором она объявлена. Та же ситуация и с другой переменной i, определённой в методе ModifyInt.

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

осуществляется по значению и изменения копии переменной i «умрут» после завершения работы данного метода.

- Чему равно значение переменной s до вызова функции ModfyString? После вызова? Почему?

Аналогично к первой переменной i, значение переменной s до и после вызова функции ModifyString

составляет «Hello, world». Но, хотя переменная s является ссылочной и вроде бы в функцию

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

2. Ответьте на следующие вопросы:

- Какие типы являются типами-значениями (value types)?

C# располагает двумя категориями встроенных типов данных: типы значений и ссылочные типы. Термин "тип значения" применяется к переменным, которые непосредственно содержат значения. Типы значений также называют простыми типами.

№п/п

Псевдоним типа

Комментарии

1.

b o o l

Логический, или булев, представляет значения ИСТИНА/ЛОЖЬ

2.

b y t e

8-разрядный целочисленный без знака

3.

c h a r

Символьный

4.

d e c i m a l

Числовой тип для финансовых вычислений

5.

d o u b l e

С плавающей точкой двойной точности

6.

f l o a t

С плавающей точкой

7.

i n t

Целочисленный

8.

l o n g

Тип для представления длинного целого числа

9.

s b y t e

8-разрядный целочисленный со знаком

10.

s h o r t

Тип для представления короткого целого числа

11.

u i n t

Целочисленный без знака

12.

u l o n g

Тип для представления длинного целого числа без знака

13.

u s h o r t

Тип для представления короткого целого числа без знака

-Какие типы являются типами-ссылками (reference-types)? String, Object. Также, ссылочные типы определяются классами, делегатами, массивами... Переменные ссылочных типов содержат ссылки на реальные значения. Однако String ведет себя немного по-другому.

-Какие различия между типами-значениями и типами-сылками? Тип-значения хранит данные непосредственно, а ссылочный тип хранит ссылку на значение.

-В чем проявляется эта разница в примере types.cs? ModifyInt(i); - такая запись означает, что при вызове метода static void ModifyInt(int i), в качестве параметра передается не сама переменная i, а копия ее значения и, соответственно, запись {i = 99;} не изменяет прежнего значения ранее объявленной переменной i. Если абстрагироваться от вопроса об области видимости переменных, то участок кода

static void ModifyInt(int i)

{

i = 99;

}

можно было бы переписать следующим образом:

static void ModifyInt(int j)

{

j = 99;

}

, тем самым показав, что j – это совсем другая переменная.

В то же время запись int i = 10; говорит об инициализации переменной типа-значения.

- Где размещаются переменные типов-значений (values-types)? В области оперативной памяти,

называемой стеком.

- Где размещаются переменные типов-ссылок (reference-types)? В области оперативной памяти,

называемой управляемой кучей.

-Как создать новый тип-значение (values-type)? Новый тип-значения создается при объявлении структуры.

-Как создать новый тип-ссылку (reference-type)? Используя ключевое слово class.

3. Изучите, скомпилируйте и запустите пример simpletypes.cs, объясните как он работает, имея в

виду концепцию «все есть объект».

using System;

class SimpleTypes

{

static public void Main(string[] args)

{

int i = 10;

Console.WriteLine("i is a " + i.GetType() + " and has a value of " + i); SimpleAsObject(i);

Console.WriteLine("i is a " + i.GetType() + " and has a value of " + i);

}

static void SimpleAsObject(System.Int32 j)

{

Console.WriteLine("j is a " + j.GetType() + " and has a value of " + j); j = 32;

Console.WriteLine("j is a " + j.GetType() + " and has a value of " + j);

}

}

Вход в программу происходит с инициализацией переменной i, которая имеет тип интежер.

Далее выводится на консоль ее тип – тип System.Int32. Это правильно, поскольку такой тип имеет псевдоним int (short – System.Int16, long – System.Int64). После этого управление передается методу

SimpleAsObject, который получает в переменную j значение из переменной i, тоже обыкновенного типа integer. Выводится на консоль ее тип, изменяется ее содержимое и снова – на консоль ее тип. Далее управление возвращается в Main и опять консоль принимает вывод типа переменной i.

Значение переменной i, переданное в качестве параметра методу SimpleAsObject, передается по значению, то-есть копией переменной i.

-Какой тип у переменной i? Int32.

-Какой тип у переменной j? Int32.

-Объясните ваши наблюдения по поводу типов переменных i и j.

Все встроенные С#-типы (например, int и double) в действительности являются лишь псевдонимами (т.е. другими именами) для структур, определенных в среде .NET Framework.

Компания Microsoft заявляет, что понятия С#-типа и .NET-типа структуры неразличимы. Первое

— просто еще одно имя для другого. Поскольку С#-типы значений поддерживаются структурами,

они имеют члены, определенные для этих структур. Эти структуры определены в пространстве имен System. Таким образом, составное имя для структуры Int32 "звучит" как System.Int32. В виду этого тип обеих переменных integer. Или – System.Int32 по стандарту .NET. Поэтому оператор static void SimpleAsObject(System.Int32 j) возможно переписать как static void SimpleAsObject(int j)

без изменения результата работы кода.

4. Рассмотрим превращение типов значений в типы ссылки (boxing) и извлечение типов-значений из соответствующих им типов-ссылок (unboxing) на следующем примере.

int i = 123;

В этом случае переменная i располагается на стеке. object j = i;

Здесь неявно вызывается операция превращения типа-значения в тип-ссылку.

Скомпилируйте следующий код:

using System;

class BoxingTest

{

public static void Main()

{

int i = 123;

object o = i; //implicit boxing i = 456;

Console.WriteLine("The value-type value = {0}", i); Console.WriteLine("The object-type value = {0}", o);

}

}

В результате работы программа печатает следующее:

The value-type value = 456

The object-type value = 123

Вопросы:

- почему переменная типа-ссылки (reference type) o содержит старое значение?

Дело в том, что исходя из ниже приведенной схемы спецификации с#,

значения переменной i и переменной o – это два разных участка памяти (стек и управляемая куча соответственно). И изменение значения одной из них не влияет на изменение второй, поскольку при преобразовании boxing создается в куче копия переменной i и ее ссылка заносится в переменную о.

- что такое boxing и unboxing? Boxing используется для хранения типов-значений в управляемой куче. Это процесс неявного преобразования типа-значения в тип-ссылку. Если ссылку типа object

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

Unboxing – обратный процесс явного преобразования объектного типа в тип-значение. Мы можем совершить процесс распаковки лишь над той переменной, которая была ранее упакована.

-boxing выполняется неявно (implicit) или явно (explicit)? Implicit по умолчанию или explicit при явном приведении типов.

-unboxing выполняется неявно (implicit) или явно (explicit)? explicit

Приведите пример для обоих вариантов.

int i = 123;

// a value type

object o = i;

// boxing implicit

int j = (int) o;

// unboxing explicit

int i = 123;

 

object o = (object) i;

// boxing explicit

o = 123;

 

i = (int) o;

// unboxing explicit

5. Почему класс String называется неизменяемым (immutable)? Что означает «неизменяемый»

(immutable)? Это означает что стринговые переменные хотя и хранят значения типа-ссылки, но являются неизменными – изменяя строку мы тем самым создаем совершенно новую строку.

Потому строки не демонстрируют поведения, характерного для ссылочных типов.

6. Объясните, почему в следующем примере будет выведена строка

“Hello, world. I wasn’t trimmed!” (обратите внимание на пробелы), а не строка

“Hello, world. I wasn’t trimmed!”

static void Main()

{

string s = “Hello, world. ”; s.Trim();

Console.WriteLine(s + “ I wasn’t trimmed!”);

}

Потому, что тип string является ссылочным типом, но при этом неизменяемым. Например, у

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

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

Для того, что б на консоль выводился второй вариант, необходимо строку s.trim();

переписать так s=s.trim();. Этим самым мы изменили содержимое именно той области памяти,

на которую ссылается переменная s (ну и, конечно, на консоль можем выводить строку “Hello, world. I wasn’t trimmed!” посредством записи Console.WriteLine(s.trim() + “ I wasn’t trimmed!”);,

однако переменная s все равно будет содержать старое (начальное) значение).

2.Массивы. Коллекции. Структура приложения.

1.Может ли быть более одной точки входа в программу? Какие четыре варианта сигнатуры могут быть у точки входа?

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

/main вместе с полным именем (включая пространства имен) класса, к которомуотноситсяметод

Main():cscConsoleApplication3.cs /main:ProstName.MainExample.

Что касается сигнатуры (имя метода со списком его параметров)

Варианты:

static void Main()

{

}

static void Main(string[] args)

{

}

static int Main()

{

}

static int Main(string[] args)

{

}

2. Почему нижеприведенный пример не компилируется и какая ошибка будет получена?

class MainExample

{

static void Main(string[] args)

{

}

static int Main()

{

return 0;

}

}

-has more than one entry point defined: 'MainExample.Main(string[])' -has more than one entry point defined: 'MainExample.Main()'

Этот код не компилируется потому, что в тексте программы присутствует два раза ключевое слово main и компилятор не знает, где именно находится точка входа в программу.

Почему не будет компилироваться следующий пример?

class MainExample

{

static void Main(string[] args)

{

}

static int Main(int[] args)

{

return 0;

}

}

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

входа в программу, а именно тип данных, передаваемых методу Main, не может быть отличным от string.

3. Используя написанный ниже метод Main, напишите новый метод ModifyString, который изменяет переменную s, присваивая ей значение “Hello, I’ve been modified,” так, чтобы строчка Console.WriteLine,

которая вызывается в методе Main печатала Hello, I’ve been modified,”.

static void Main()

{

string s = “Hello, world”;

// Insert your call to ModifyString here Console.WriteLine(s);

}

Пример:

using System;

class SimpleTypes

{

static void Main()

{

string s = "Hello, world";

ModifyString(ref s);

// Insert your call to ModifyString here

Console.WriteLine(s); Console.ReadLine();

}

static void ModifyString(ref string s)

{

s="Hello, I’ve been modified";

}

}

Или

using System;

class SimpleTypes

{

static void Main()

{

string s = "Hello, world";

s = ModifyString(s);

// Insert your call to ModifyString here

Console.WriteLine(s); Console.ReadLine();

}

static string ModifyString(string s)

{

return s="Hello, I’ve been modified";

}

}

Сравните вашу программу с программами, написанными другими участниками форума.

4. Напишите программу, отображающую все аргументы командной строки, с которыми она вызывается.

Пример:

using System;

class CLDemo

{

public static void Main(string[] args)

{

Console.WriteLine("Командная строка содержит " +

args.Length + " аргументов. ") ;

Console.WriteLine("Вот они: " ) ;

for(int i=0; i<args.Length; i++) Console.WriteLine(args[i]);

Console.ReadLine();

}

}

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

При запуске программы с командной строки возможна передача в нее (программу) одного или нескольких аргументов, число которых не ограничено. Аргументы записываются через пробел по одному по порядку. Тип аргументов возможен только один – string. Эти аргументы помещаются в массив под названием args, но возможно и любое другое допустимое имя.

public static void Main(string[] args) public static int Main(string[] args)

-Для чего нужно значение, которое может возвращать метод Main?

Чаще всего, значение, которое возвращает метод Main необходимо для того, что бы определить, как и с какими возможными ошибками выполнилась программа. Обычно, если метод

Main, например, возвращает 0 (тип int), то это значит, что программа выполнилась корректно.

Если любое другое число, - с ошибками. Типы возвращаемых методом Main значений могут быть integer, или void.

5. Рассмотрим пример на изменение размера массива.

Пусть есть такой массив:

int[] a = new int[] { 10, 20, 30, 40, 50 };

Напишите программу на C#, которая удлиняет этот массив до 10-ти элементов от 10 до 100. Следующее решение не засчитывается:

int[] a = new int[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };

Пример:

/*Эта программа начинается с создания коллекции целочисленных значений. Затем вызывается метод ToArray (), который принимает в качестве параметра тип int. Это обеспечивает создание массива целочисленных значений. Поскольку в качестве типа значения, которое возвращает метод ToArray (),по умолчанию указан тип Array, содержимое создаваемого массива должно быть приведено к типу int[].*/

using System;

using System.Collections;

class ArrayListToArray {

public static void Main() {

int[] a = new int[5] { 10, 20, 30, 40, 50 }; ArrayList ad = new ArrayList();

// Добавляем элементы в динамический массив. for (int x = 10; x <= 100; )

{

ad.Add(x); x = x + 10;

}

//или for (int i = 1; i <= 10; i++) al[i-1] = i * 10;

Console.Write("Содержимое массива a: "); foreach (int i in a)

Console.Write("|" + i + "| "); Console.WriteLine("\n");

Console.Write("Содержимое динамомассива: "); foreach(int i in ad)

Console.Write("|" + i + "| " ) ; Console.WriteLine("\n");

//Создаем обычный массив aa из динамического ad. int[] aa = (int[]) ad.ToArray(typeof(int));

//В переменную а заносим ссылку на область памяти, хранящую массив aa a = aa;

//Выводим элементы массива a

Console.Write("Новое cодержимое массива a: \n\n"); for(int i=0; i<a.Length; i++)

Console.WriteLine("a[ " + i + " ] = " + a[i]);

Console.ReadLine();

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]