Учимся C#. Ведро третье

    Результаты отзывов


    Про аудиторию


    Так ка много комментариев было по этому поводу, то решил сделать последнюю попытку. Надеюсь на фидбек в комментариях — получилось «Для Всех» или нет.

    Про книги


    После прочтения комментариев решил опубликовать список книг, которые там рекомендовались:
    C# 2008. Ускоренный курс
    CLR via C#
    C# и платформа .NET
    C# 2.0. Полное руководство

    Про разное


    Были вопросы по поводу скорости Mono. на днях нашёл ссылку, на который есть небольшой тест. geekswithblogs.net
    Тестирование проводилось на более ранних версиях, но я думаю ситуация не глобально изменилась. ИМХО

    Ну а теперь давайте продолжим обучение…

    Сложные типы


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

    Типы по значению


    Структуры


    В C# структура — это особый тип класса. Поскольку структура размещается в стеке, она может создаваться и копироваться более эффективно, чем класс. Рассмотрим небольшую структуру:
    1. public struct Subscriber
    2. {
    3.  public long SubID;
    4.  public string FirstName;
    5.  public string LastName;
    6.  public string MiddleName;
    7.  public decimal Balance;
    8. }

    Если нам понадобится скопировать из одной структуры в другую, то просто поставим знак равенства. Давайте создадим один объект Subscriber, Sub1, и установим значеи полей. После этого скопируем значение всех полей из одной структуру в другую, Sub2:
    1. Subscriber Sub1;
    2. Subscriber Sub2;
    3. //Инициализируем структуру и заполним поля
    4. Sub1 = new Subscriber();
    5. Sub1.FirstName = "Вася";
    6. Sub1.LastName = "Пупкин";
    7. Sub1.MiddleName = "Какой-то";
    8. Sub1.Balance = 100;
    9.  
    10. //И теперь одной строкой копируем содержимое одной структуры в другую
    11. Sub2 = Sub1;

    Заметили, что мы использовали new, хотя струтктура является типом по значению? Просто доступ к структуре возможен до вызова операнда new.
    Помимо копирования, структура делает более аккуратным вызов функций.

    Если вы гуру C или C++, то будьте осторожны — они изменились! В C/C++ единственное различие между классом и структурой заключалось в том, что они были общедоступными, а не закрытыми.
    Струтура в C# совершенно новая игрушка, не только по тому, что их члены по умолчания являются закрытыми, но экземпляры структур и экземпляры классов размещаются в различных местах памяти.
    Структуры могут поддерживать большинство функций класса (хотя и не поддерживает наследование реализаций), но их необходимо использовать осторожно. Лучше всегшо структуры годятся для предоставления небольших объектов.

    Перечисления


    Перечисления (enumerations) — целочисленные типы, которые определяет пользователь. При обьявлении перечислений вы специфицируете набор допустимых значений, которые могут принимать экземпляры перечислений. Кроме того нужно присвоить значениям интуитивно понятные имена.
    В дальнейшей работе перечисления могут сыграть очень важную роль и облегчить жизнь программисту. Обьявляются перечисления вот так:
    1. public enum DaysOfWeek
    2. {
    3.  Monday = 0,
    4.  Tuesday = 1,
    5.  Wednesday = 2,
    6.  Thursday = 3,
    7.  Friday = 4,
    8.  Saturday = 5,
    9.  Sunday = 6
    10. }

    Здесь мы используем целые значения, которые соответствуют дням недели. Доступ к конкретному дню недели можно получить вот так: DaysOfWeek.Wednesday вернет 2. Обычно перечисления используют в тех случаях, когда нужно передавать соответствующее значение методу, который будет проходить по всем значениям спомощью switch и выдавать соответствующий результат. Про switch более подробно мы поговорим чуть позднее, а пока давайте посмотрим пример:
    1. class Program
    2.   {
    3.     static void Main(string[] args)
    4.     {
    5.       WriteText(DaysOfWeek.Sunday);
    6.       Console.ReadLine();
    7.     }
    8.  
    9.     static void WriteText(DaysOfWeek days)
    10.     {
    11.       switch (days)
    12.       {
    13.         case DaysOfWeek.Monday:
    14.           Console.WriteLine("Понедельник - день тяжелый!");
    15.           break;
    16.         case DaysOfWeek.Tuesday:
    17.           Console.WriteLine("Вторник - это значит что понедельник уже прошел!");
    18.           break;
    19.         case DaysOfWeek.Wednesday:
    20.           Console.WriteLine("Среда! Средина недели!");
    21.           break;
    22.         //И так далее...
    23.       }
    24.     }
    25.   }


    Типы по ссылке


    Классы


    Классы являются основным определяемым пользовательским типом в C# и платформе .NET. Практически все программы имеют по крайней мере один класс (теоретически можно использовать структуру вместо класса), который содержит метод Main() — точку входа в программу.
    Классы — это составные типы данных, которые включают в себя члены данных и функции. классы так же содержат в себе вложеные типы данных. Более подробно про классы поговорим через одно «ведро». =)

    Интерфейсы


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

    Делегаты


    Делегаты — это типы, которые ссылаются на методы. Они похожи на указатели функций в C++, но разрешают создавать экземпляр класса и вызывать как статичные методы, так и методы конкретного экземпляра класса.
    Для новичков пока ещё рано вникать в тонкости, поэтому просто запомните название — мы ещё вернёмся к ним.

    Массивы


    Массив задает способ организации данных. Массивом называют упорядоченную совокупность элементов одного типа. Каждый элемент массива имеет индексы, определяющие порядок элементов. Число индексов характеризует размерность массива.
    В языке C#, как и во многих других языках, индексы задаются целочисленным типом.
    В языке C# снято существенное ограничение языка C++ на статичность массивов. Массивы в языке C# являются настоящими динамическими массивами.

    Объявление массивов

    Рассмотрим, как объявляются одномерные массивы.

    Объявление одномерных массивов

    Общая структура объявления:
    [<атрибуты>] [<модификаторы>] <тип> <имя>;

    Забудем пока об атрибутах и модификаторах. Объявление одномерного массива выглядит следующим образом:
    <тип>[] <имя>;

    Заметьте, в отличие от языка C++ квадратные скобки приписаны не к имени переменной, а к типу. Они являются неотъемлемой частью определения класса, так что запись T[] следует понимать как класс одномерный массив с элементами типа T.
    1. //объявление массива
    2. int[] Integers;

    Это пример объявления массива. Так же можно инициализировать массив используя new:
    1. //Создаём массив из 32 значений типа int
    2. int[] Integers = new int[32];

    Для получения доступа к элементу массива применяется обычный синтаксис:
    1. Integers[0] = 24;

    C# позволяет нам создавать массивы не инициализируя их, поэтому они могут менять размер в ходе выполнения программы.
    1. int[] Integers;
    2. Integers = new int[32];

    Массивы в C# сохранили возможность, как и в C/C++, инициализации значений, перечисленых в фигурных скобках.
    1. string[] Privet = {"раз", "два", "три"};
    2. //Что эквивалентно
    3. string[] Privet = new string[] {"раз", "два", "три"};

    Однако есть и подводные камни! Например для установки размера массива нельзя использовать переменную:
    1. int len = 3;
    2. //Не скомпилируется
    3. string[] Privet = new string[len] {"раз", "два", "три"};
    4.  
    5. /* Однако мы можем использовать константу */
    6.  
    7. const int len = 3; //Это константа
    8. //А теперь скомпилируется
    9. string[] Privet = new string[len] {"раз", "два", "три"};


    Что интересного можно делать с массивом?
    Узнаем длину массива:
    1. int Dlina = Massiv.Length;
    2. //ToString() - переводит из int в string
    3. Console.WriteLine(Dlina.ToString());

    Отсортируем:
    1. //Наш массив передаётся в качестве параметра методу Sort()
    2. Array.Sort(Massiv);

    Изменяем порядок:
    1. //Наш массив передаётся в качестве параметра методу Reverse()
    2. Array.Reverse(Massiv);

    и ещё многое другое…

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

    Итак на сегодня думаю достаточно. Не поверите, но пропустил один день из-за того, что после печатания мною этой (аналогичной) статьи в ХабраРедакторе что-то заглючил браузер и я не успел сохранить. Очень сильно разозлился и пошёл спать. Эмоции…
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 51

      +2
      Интерфейсом в C# является тип ссылок

      Вы либо плохо говорите по-русски; либо не понимаете, что пишете; либо вы промт; либо уже вечер и вы жутко устали — тогда в следующий раз отложите пост на утро.
        +1
        Спасибо, исправил. Надо было отложить пост. Просто после часа писанины не так было легко потом всё 100% проверить, что мне собственно и не удалось.
        –1
        Однако есть и подводные камни! Например для установки размера массива нельзя использовать переменную

        В чём смысл примера после этой фразы? Показать что вне зависимости от того, делаем ли мы константой неиспользованную переменную len, массив так создать не получится?
        Или там что-то другое должно быть?
          0
          Извините, что Вы, что постом выше правы — надо было отложить пост до утра. Сейчас исправлю.
            0
            Ничего, не извиняйтесь. Если бы не завтрашний экзамен, сегодняшняя 4 чашка Java выглядела бы так же :)
              0
              [offtop]
              Добавил в други. Есть интересное предложение для тебя.
              [offtop]
        • UFO just landed and posted this here
            0
            Недописал одно слово. Исправил.
              +2
              Это не бред. Значимые типы не поддерживают наследование в вашем коде. То, что вы написали, это не наследование, а реализация интерфейса, это разные вещи. При наследовании вы получаете все поля, методы, свойства и т.п., определенные в базовом классе, методы у вас идут уже реализованные. При реализации интерфейса вы должны сами создать реализацию методов интерфейса, сама запись B: IA значит не более того, что вы обязуетесь создать в структуре B методы, описанные в IA. Интерфейс по сути — это просто контракт, без его реализации в определении интерфейса.
              • UFO just landed and posted this here
              0
              Не знаю как для всех, но для меня получилось (с учетом упомянутых выше огрехов)

              >Надо было отложить пост. Просто после часа писанины не так было легко потом всё 100% проверить, что мне собственно и не удалось.
              Угу, хорошее решение дать посту «отлежаться». Думаю мы можем потерпеть небольшую паузу в выпусках, а периодичность по идее измениться не должна после «отлежевания» первого

                0
                string[] Privet = «раз, два, три».Split(',');

                а вообще у меня компилируется и так:

                string[] Privet = new string[] {«раз», «два», «три»};
                и так: string[] Privet = new {«раз», «два», «три»};

                Впрочем енто может фенечка дотнета 3.5
                  0
                  массивы в .Net не являются полностью динамическими, хоть их и можно ресайзить.
                  (http://www.gotdotnet.ru/Forums/Windows/18316.aspx)

                  советую юзать Generics.
                    0
                      0
                      Generics сами по себе никакого отношения к динамичности и к массивам, и даже к коллекциям не имеют. Просто удобно и производительно создавать типизированные коллекции, используя generic'и. Динамические коллекции в .NET были и до дженериков — например, ArrayList, другой вопрос, что типизированные коллекции (List?lt;T> и т.п.) — лучше.
                        0
                        ммм наверно не так выразился…
                        я противопоставил генерики массивам, а это ошибочно.

                        Я имел ввиду что зачастую если выходим за рамки массивов или хотим большего удобства,
                        лучше юзать ArrayList/List
                          0
                          Да, как-то за последние 2 года ни разу «чистые» массивы не использовать, всё какие-либо List:)
                            0
                            я иногда использую для хранения очередей определенных, когда например много потоков выхватывают для себя работу из массива int к примеру…
                        0
                        Я думаю стоит вернее выразиться, ибо не все Generics — коллекции ;).
                        Есть коллекции Generics, которые сейчас очень активно используются, но те кто начинал с первой версии помнят, что там Generics не было, а были коллекции аля ArrayList, которые работали с типом Object. А тип ArrayList никуда не делся :).
                          +1
                          Забыл дописать что Generics — это всё-таки аналог шаблонов в С++.
                            0
                            Замечу следующее: что разница между шаблонами в C++ и обобщениями в C# в том что их расширение происходит динамически, а шаблонов в C++ статически.
                            И получаем выигрыш от использования обобщений с типами значений. В том же ArrayList приходилось упаковывать и распаковывать значения, этого не случается при использовании обобщений для типов значений.
                              0
                              Я предпочитаю использовать термины «во время компиляции» и «во время исполнения», это на мой взгляд понятнее звучит. Хотя и то и то определене является правильным. Да, различий намного больше если верить MSDN.
                            0
                            Да вы правы :)
                          0
                          О, уже интереснее) я думаю, полезен бы был краткий список основных классов (ну вот типа String, Array и что там еще часто используется) и их основных (самых используемых) методов, просто чтобы представлять что есть, не читать же всю документацию.
                            0
                            ссылочке на сравнение производительности скоро уж 4 года, каково же актуальное положение вещей?
                              0
                              спасибо за статью, но я немного позанудствую

                              класс (теоритически можно использовать структуру вместо класса)
                              правильно теоретически,
                                0
                                по поводу enum'ов не совсем корректно.

                                DaysOfWeek.Wednesday вернет не 2.
                                Для преобразования в int нужен явный каст — (int)DaysOfWeek.Wednesday.
                                А используя метод ToString() можно получить его название

                                Поэтому работая со стрингами (и всякими String.Format) помнить об этом.
                                Пример:
                                Console.WriteLine(«One — » + DaysOfWeek.Wednesday + ", Two — " + (int)DaysOfWeek.Wednesday);
                                Выведет «One — Wednesday, Two — 2»
                                  0
                                  ИМХО, сумбурный пост, который только добавит путаницы в головах неофитов C#. Многие упомяные вещи рассмотрены настолько вскользь, что можно было их и не упоминать, все равно в книгах написано лучше. Для начинающих могу дать совет — исользуйте Reflector и читайте с его помощью код, написанный опытными C#-программистами, тот же код самого .NET. Там уже будут хорошие примеры использования всего, чего угодно.
                                    +1
                                    ИМХО, сумбурный пост, который только добавит путаницы в головах неофитов C#. Многие упомяные вещи рассмотрены настолько вскользь, что можно было их и не упоминать, все равно в книгах написано лучше. Для начинающих могу дать совет — исользуйте Reflector и читайте с его помощью код, написанный опытными C#-программистами, тот же код самого .NET. Там уже будут хорошие примеры использования всего, чего угодно.
                                      0
                                      Сорри за дубль.
                                        0
                                        Вы знаете, читать код с помощью рефлектора конечно удобно, но неофитам это будет довольно сложно. Притом MSDN содержит, на мой взгляд, довольно не плохие примеры, которые стоит использовать, ну или хотя бы просмотреть.
                                          +1
                                          Возможно, сложно, я с этим не спорю. Просто я сам начинал так, поэтому и дал совет использовать Reflector. MSDN, конечно, никто не отменял. (Правда, некоторые примеры кода там написаны индусами, и, при всем моем ненеуважении к этой нации, написаны в индусском стиле:) )
                                            0
                                            Хе, ну если уж нато пошло, то в разработке .Net индусы тоже участие принимали, так что это палка о двух концах ;).
                                            А вы довольно грамотны в этом отношении, не знаю сколько на практике, но в теории разбираетесь очень хорошо. Приятно общаться :).
                                            Повысил вам кучку в карме.
                                      0
                                      Попорядку:
                                      В C# структура — это особый тип класса.

                                      Вы меня простите, но это бред. Структура — определённый пользователесь value-type, но ни как не тип класса.
                                      DaysOfWeek.Wednesday

                                      Вернёт Wednesday, но никак не 2. Может вернуть 2 если будет приведение к типу int… Выше про это писали уже в комментах.

                                      Затем объясните, почему у вас
                                      //Что эквивалентно
                                      string[] Privet = new string[] {«раз», «два», «три»};

                                      вроде всё «в шоколаде», а парой строк вниз, стоит пометка что код не компилируемый?
                                      //Не скомпилируется
                                      string[] Privet = new string[] {«раз», «два», «три»};


                                      Вот ещё
                                      Массивы в языке C# являются настоящими динамическими массивами.

                                      А может лучше было указать, что это класс?

                                      Я конечно прочитал, что статья не вычитана и ещё сырая. Но думаю стоило бы повременить и подготовить качественный материал.
                                      Простите мне мою излишнюю эмоцианальность :).
                                        0
                                        >>Вы меня простите, но это бред. Структура — определённый пользователесь value-type, но ни как не тип класса.

                                        Три книги говорят об обратном. Тем более книги не уровня «C# за пять минут»

                                        >>Вернёт Wednesday, но никак не 2. Может вернуть 2 если будет приведение к типу int… Выше про это писали уже в комментах.

                                        Дайте мне ссылку где про это посмотреть? Енумами пользуюсь очень редко, но книги и статьи в интернете говорят опять таки обратное? Например вот devoid.com.ua/csharp/csharp-for-beginners/enumerations-in-csharp.html

                                        >>вроде всё «в шоколаде», а парой строк вниз, стоит пометка что код не компилируемый
                                        Извините. Сейчас исправлю. Это следствие копи-паста предыдущих строк

                                          0
                                          1. Хе, со мной можно поспорить, с MSDN — нет ;)
                                          structure
                                          A user-defined value type. Like a class, structures can contain constructors, constants, fields, methods, properties, indexers, operators, and nested types. Unlike classes, however, structures do not support inheritance. See also: class, field, indexer, nested type, property, value type.

                                          2. А зачем ссылку, можно обратиться к отладчику(прошу заметить, что отладчик не использует ToString(), а отображает как оно есть на самом деле)

                                          Я думаю по картинке видно что содержится :)
                                            0
                                            Хм… Странно. Значит книги нас обманывают о_О
                                            На работе есть только одна книга — C# для профессионалов (которая в двух томах) и она
                                            , я думал, достаточно авторитетна.
                                              0
                                              Один из авторов этой книги, случайно не Ватсон?
                                              Знаете, наверное, в чём проблема. В том что книги переводят люди, которые технически безграмотны(не все книги, но есть отдельные экземпляры). Вот, как раз, один из этих печальных примеров и есть Ватсон. Может его книги и не плохи, но перевод у них отвратительный.
                                            0
                                            Важное дополнение — память под объекты классов выделяется в heap'e, а под структуры напрямую в стеке.
                                            Именно в этом причина того, что не особенно рекомендуется делать структуры большими-память в стеке не резиновая :)
                                          0
                                          > //ToString() — переводит из int в string

                                          я бы сказал, что это общий метод для всех классов, наследуемый от Object, и переводит все что угодно в String
                                            0
                                            Я это уже указывал, когда говорил про Object в прошлом «ведре»
                                            +1
                                            Надо добавить еще про Array.Sort, что он сортирует с использованием Comparer'а по умолчанию. То есть если пользователь пишет свой тип, то ему необходимо определить интерфейс IComparable, иначе, при вызове Sort() кинется эксепшн.
                                              +1
                                              Насчет книг — возьмите Троелсена, лучше в оригинале

                                              Самая лучшая книжка для изучения .net с нуля. Пригодится в ваших статьях-выжимках.

                                              Немного непонятен, вы простите меня конечно, смысл ваших статей. Изучать c# по ним, в лучшем случае, нужно с опаской — потому как неясен ни ваш опыт, ни ваши цели. Я так понял, вы хотите написать еще одну книгу по .net c# — это похвально, но хватит ли сил и как вы оцениваете полноту материала?
                                                0
                                                У меня небольшое пожелание: может есть смысл в начале каждой новой статьи приводить ссылки на все предыдущие?
                                                  0
                                                  Однако есть и подводные камни! Например для установки размера массива нельзя использовать переменную
                                                  Если статья рассчитана на начинающих, можно было бы рассказать, как всё-таки сделать подобное с переменной, а то остаётся отрывочные сведения после прочтения :) Всё-таки создание массива длинной, заданной не на этапе компиляции — намного более распространённое дело, чем ощущение разницы между классом и структурой.
                                                    +1
                                                    дополнения/исправления.

                                                    «Струтура в C# совершенно новая игрушка, не только по тому, что их члены по умолчания являются закрытыми, но экземпляры структур и экземпляры классов размещаются в различных местах памяти.»
                                                    Первое неверно — и в классах, и в структурах члены по умолчанию приватные. Отличие классов и структур только в хранении в памяти и том, что из этого следует (отсутствие наследования etc)

                                                    «Здесь мы используем целые значения, которые соответствуют дням недели. Доступ к конкретному дню недели можно получить вот так: DaysOfWeek.Wednesday вернет 2»
                                                    Про enum'ы выше уже говорили, можно добавить, что синтаксис позволяет явно задать тип enum'а, например 'enum X: byte { a = 0 }', но даже в таком варианте нужно явное приведение к численным типам. Дополнительную информацию о конкретном экземпляре enum'а можно узнать через класс Enum.

                                                    «Делегаты — это типы, которые ссылаются на методы. Они похожи на указатели функций в C++, но разрешают создавать экземпляр класса и вызывать как статичные методы, так и методы конкретного экземпляра класса.»
                                                    Все делегаты являются наследниками MulticastDelegate и содержат в себе набор пар (ссылка на объект; ссылка на метод объекта). Делегаты ничего не создают.

                                                    «C# позволяет нам создавать массивы не инициализируя их, поэтому они могут менять размер в ходе выполнения программы.»
                                                    не совсем так. приближенно — все массивы являются типом Array, и в вашем примере разделено обявление переменной объекта и её инициализация конструктора. после создания размер не меняется.
                                                      0
                                                      Первое неверно — и в классах, и в структурах члены по умолчанию приватные
                                                      Автор об этом и говорит, противопоставляя C# и C++, где члены структур публичны по умолчанию.
                                                    • UFO just landed and posted this here
                                                        0
                                                        По повожу переменных не соглашусь, а вот про транслит всё просто — хотелось как можно понятней. Дело в том, что когда я обзываю переменную транслитом, то я хочу всего лишь показать, что это имя мы сами придумали, а не какое либо слово специальное. В универе у студентов часто возникала с этим проблема на момент понимания.
                                                      • UFO just landed and posted this here

                                                        Only users with full accounts can post comments. Log in, please.