Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Работа со строками в .NET. Часть 2. Неизменяемость (immutable) строк.


Информационный Канал Subscribe.Ru

Профессинальное программирование на .NET


Работа со строками в .NET

Часть 2

Важнейшим свойством строк в .NET является их неизменяемость (immutable). Это означает что созданную строку невозможно изменить. Следствием этого является то, что любой метод класса String не изменяет его. Например:

string s = "Some String"; Console.WriteLine(s.ToUpper());

В этом примере создается строковый объект s, у которого вызывается метод ToUpper(). Это приводит к созданию нового строкового объекта ("SOME STRING"), который выводится на консоль. При этом s не изменилось.  Часто, для достижения результата, приходится вызывать последовательно несколько методов класса String:

string newString = s.Trim().Substring(10, 20).ToLower();

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

Однако, если вам необходимо часто формировать строки в своем приложении, то множество промежуточных строковых объектов все же может сказаться на производительности.
Для этого в .NET Framework имеется специальный класс StringBuilder. Он позволяет модифицировать содержащуюся в нем строку без потери производительности (не создавая промежуточных объектов).

Для этого используются следующме методы класса: Append, AppendFormat, Insert, Remove, Replace.

Как же работает класс StringBuilder? Джеффри Рихтер в своей книге "Программирование на платформе .NET FRAMEWORK" пишет:
У объекта StringBuilder предусмотрено поле с ссылкой на массив структур Char. Используя члены StringBuilder, вы можете эффективно манипулировать этим массивом, сокращая строку и изменяя символы строки. При увеличении строки, представляющей ранее выделенный массив символов, StringBuilder автоматически выделит память для нового, большего по размеру массива, скопирует символы и приступит к работе с новым массивом. Прежний массив станет мусором.

Возможно, что в бета версии .NET, по которой Рихтер писал свою книгу, так и было. Но давайте заглянем сами в класс StringBuilder (с помощью утилиты .NET Reflector, о которой я рассказывал в первом выпуске). Класс содержит следующее объявление:
internal string m_StringValue;

Как вы помните, модификатор доступа internal (внутреннмй) эквивалентен public для классов той же сборки и private для классов других сборок.
Далее, методы, модифицирующие строку, вызывают внутренние небезопасные (internal unsafe) методы класса String, которые манипулируют строкой напрямую:

internal unsafe void ReplaceCharInPlace(char oldChar, char newChar, int startIndex, int count, int currentLength)
{
  int num1 = startIndex + count;
  fixed (char* local1 = &this.m_firstChar)
  {
    for (int num2 = startIndex; num2 < num1; num2++)
    {
      if (local1[num2] == oldChar)
      {
        local1[num2] = newChar;
      }
    }
  }
}

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

В заключение, хотелось бы рассказать немного об очень полезном методе Format класса String. Он, также, как и метод AppendFormat класса StringBuilder позволяет эффективно сформировать строку из строки со спецификаторами формата и строковых представлениях объектов. На самом деле, в методе Format создается объект StringBuilder и вызывается его метод AppendFormat. Это позволяет вам сэкономить несколько строк кода.
Вот одна из наиболее часто используемых перегрузок метода Format:
public static string Format( string format, params object[] args );

Вот как правильнее написать пример с перевод строки из предыдущего выпуска:
String s = String.Format("Line{0}New Line", Environment.NewLine);

Вот еще один пример:
int x = 10; int y = 20; String s = String.Format("{0} + {1} = {2}", x, y, x + y);

Если вы не знакомы со спецификаторами формата, обязательно прочтите о них в MSDN. Это очень удобное и эффективное средство для форматирования строк.

На этом краткий обзор строк в .NET пока завершен. Я многого не рассказал, но для первого знакомства этого вполне достаточно. Не думаю, что я напишу когда-нибудь полное руководство по работе со строками, но к некоторым моментам я еще вернусь в следующих выпусках рассылки.

Инструменты разработчика

Часто возникает необходимость провести эксперимент над небольшим учатком кода (например, проверить фрагменты из сегодняшнего выпуска). Но создавать новый проект немного лень. Для этого я использую Snippet Compiler (www.sliver.com), который позволяет запускать фрагменты (snippet) кода без потери времени на создание проекта. Я часто использую его для проверки спорных вопросов работы .NET Framework.

Логическая задача

Сначала ответ на задачу из предыдущего выпуска про бильярдные шары.

Имеется 13 овершенно одинаковых с виду бильярдных шаров, из них ровно один бракованный, причем неизвестно, легче он остальных или тяжелее. Требуется найти этот шар за три взвешивания. Весы - стандартные для задач этого типа: две чашечки без гирь.

Ответ.
Сначала приведу стандартный ответ (наверное, придуманный автором) для этой задачи (часто в условии речь идет не о шарах, а о монетах).

Отложим в сторону тринадцатый шар, а остальные обозначим следующим образом: FAKE MIND CLOT (фальшивый разум глупец). Теперь взвешиваем одну четверку против другой (буквы обозначают шары, входящие в каждую четверку): MA DO - LIKE, ME TO - FIND, FAKE - COIN (Мамочка хочет, чтобы я нашел фальшивую монету). Теперь совершенно просто найти бракованный шар, если он входит в эти двенадцать шаров. К примеру, если результаты взвешивания были: слева легче, равно, слева легче, то бракованным может быть только шар "A", который легче других. А что если бракованным окажется все-таки отложенный нами, тринадцатый шар? Все очень просто: в этом случае при всех трёх взвешиваниях весы будут сбалансированы. К сожалению в этом случае нам не узнать легче или тяжелее тринадцатый шар, но в условии такого требования и не было :)

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

Поместим 4 шара на одну чашу весов и 4 - на другую (останется 5 шаров).
 1. Если весы в равновесии, то бракованный шар в оставшейся пятерке, а 8 шаров из первого взвешивания будем считать эталонными. Поместим на одну чашу 3 шара из пятерки, а на другую - 3 эталонных.
  1.1. Если весы снова в равновесии, то бракованный шар - среди двух оставшихся. Мы легко его найдем сравнив любой из них с эталонным.
  1.2. В противном случае бракованный шар находится среди трех шаров из пятерки и по показаниям весов мы знаем легче он или тяжелее. Поместим по одному шару из этой тройки на каждую чашу весов. Если весы в равновесии, то оставшийся шар из тройки и есть бракованный, иначе легко определяем бракованный шар, зная легче он или тяжелее остальных.
 2. Если же весы не уравновешены, то бракованный шар среди первой восьмерки, а оставшуюся пятерку будем считать эталонной. Возмем из "легкой" четверки 3 шара, а из тяжелой 2 и поместим их на одну чашу, а на другую - пять эталонных шаров.
  2.1. Если весы в равновесии, то бракованный шар среди трех, оставшихся от первой восьмерки. Тогда поместим на одну чашу единственный шар из "легкой" и любой из двух из "тяжелой". Задача свелась к окончанию варианта 1.2.
  2.2. Если весы не уравновешены, то бракованный шар среди пяти шаров с первой чаши. Более того, по положению весов, мы можем определить, находится ли он в "легкой" тройке или "тяжелой" двойке. Задача снова сводится к варианту 1.2.


Теперь давайте перейдем к сегодняшней задаче.

Еще в детстве мне попалась замечательная книга головоломок Рэймонда М. Смаллиана "ПРИНЦЕССА ИЛИ ТИГР?". Некоторые задачи я хотел бы представить вашему вниманию. Название книга получила по одной из своих глав. В этом выпуске я привожу первые три задачи из этой главы. Они очень легкие и, я надеюсь, не займут у вас много времени.


2.   Принцесса или тигр?

   У Фрэнка Стоктона есть сказка, которая называется "Принцесса или тигр?" В этой сказке один узник должен угадать, в какой из двух комнат находится принцесса, а в какой - тигр. Если он укажет на первую комнату, то женится на принцессе, если на вторую, то его (вполне возможно) растерзает тигр.

   В некотором царстве правил король. Однажды он тоже прочитал эту сказку.
-  В самый раз для моих заключенных! - сказал он своему министру. - Только я не хочу полагаться на случайности. Пусть на дверях каждой комнаты повесят по табличке, а заключенному будет кое-что сказано о них. Если узник не дурак и способен рассуждать логически, он сумеет сохранить себе жизнь и в придачу заполучить прелестную невесту.
-  Блестящая идея, ваше величество! - согласился министр.


Испытания первого дня

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

1. Первое испытание.

- А что, если в обеих комнатах сидят тигры? - спросил узник. - Что же мне тогда-то делать?
- Считай, не повезло, - ответил король.
- А если в обеих комнатах окажется по красавице? - поинтересовался узник.
- Считай, подфартило, - сказал король. - Уж это ты и сам бы мог сообразить!
- Ну, хорошо, а если в одной комнате принцесса, а в другую посадили тигра, что тогда? - не успокаивался узник.
- Вот тут-то уже все зависит от тебя! Не так ли?
- Да откуда же мне знать, где кто? - сокрушенно вздохнул узник.
   Тут король указал на таблички, прикрепленные к дверям каждой из комнат. На них было написано:

I
В этой комнате находится принцесса, а в другой комнате сидит тигр

II
В одной из этих комнат находится принцесса; кроме того, в одной из этих комнат сидит тигр

- А это правда, что здесь написано? - спросил узник.
- На одной - правда, - отвечал король, - на другой - нет.
   А вы на месте узника, какую бы дверь открыли? (Конечно, если вы предпочитаете принцессу тигру.)

2. Второе испытание.

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

I
По крайней мере в одной из этих комнат находится принцесса
II
Тигр сидит в другой комнате

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

3. Третье испытание.

   Во время этого испытания король объявил, что опять утверждения на обеих табличках одновременно либо истинны, либо ложны. Надписи же были вот какие:

I
Либо в этой комнате сидит тигр, либо принцесса находится в другой комнате
II
Принцесса в другой комнате

   Кто же обнаружится в первой комнате - принцесса или тигр? А во второй?


Вопросы? Пожелания? Пишите: olen33@gmail.com

Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.gurudotnet
Отписаться
Вспомнить пароль

В избранное