Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2213 / 889 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 2:

Обзор языка C#

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >

Список параметров

В некоторых случаях точное количество параметров заранее неизвестно; например, метод вывода Console.WriteLine может принимать как одиночные переменные известного типа, так и произвольное число объектов для печати. В С++ для этого используется аргумент "многоточие"; в C# такая функциональность реализуется с помощью специального ключевого слова params , которое должно быть последним в списке параметров метода и сопровождаться указанием типа принимаемых параметров. Если в списке параметров могут встречаться аргументы различного типа, то необходимо использовать тип object, так как любой аргумент может быть приведен к этому типу путем упаковки.

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

class Info {
  public static void Trace (string strMessage) {
    Console.WriteLine (strMessage);
  }
  public static void TraceX (string strFormat, params object[] list) {
    Console.WriteLine (strFormat, list);
  }
}

class Test {
  public static void Main() {
    Info.Trace  ("Plain vanilla string... ");
    Info.TraceX ("{0} {1} {2}", "C", "U", 2001);
  }
}

Препроцессор C#

В своей книге "Дизайн и эволюция языка С++" Бьярни Страуструп писал:

"...Я поставил себе целью изжить Cpp [препроцессор С++]. Но задача оказалась труднее, чем представлялось вначале. Сpp, возможно, и неудачен, но трудно найти ему лучше структурированную и более эффективную замену".

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

В C# эта проблема решена кардинальным образом. Препроцессор стал частью компилятора (т.е. перестал быть препроцессором в традиционном понимании этого слова), а из привычного набора макросов оставлены только следующие:

  • #define и #undef для определения идентификаторов и отмены определения (но без значений - для задания значений используется ключевое слово const )
  • Механизм условной компиляции, основанный на директивах #if , #else , #endif
  • Генерация предупреждений и ошибок с помощью макросов #warning и #error

В следующем примере мы продемонстрируем использование всех перечисленных выше механизмов препроцессора:

#define DEBUG 

#if DEBUG && DEMO
  #error You cannot build a debug demo version

class Demo {
  public static void Main() {
    #if DEBUG
      Console.WriteLine("Starting the program... ");
    #endif
  }
}

Атрибуты

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

Традиционным решением этой задачи была запись информации подобного рода в специальных файлах (например, .IDL или .DEF). В С# для этой цели используются атрибуты , которые представляют собой "примечания" к элементам исходного текста программы (классам, методам, параметрам методов и т.д.). В отличие от комментариев, информация, записанная в атрибутах, не теряется во время компиляции, а сохраняется в метаданных программы и может быть извлечена с помощью механизма рефлексии (подробнее об этом - в "лекции 14" ).

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

using System.Runtime.InteropServices;
public class AppMain {
  [DllImport("user32.dll")]
  public static extern int MessageBoxA(int handle, string message,
    string caption,int flags);
  public static void Main(){
    MessageBoxA(0, "Hello World", "Native Message Box",0);
  }
  [conditional("DEBUG")] 
  public static void SayHello() { 
    Console.WriteLine("Hello, World! "); return; 
  }
}

В этом примере используется атрибут DllImport , с помощью которого обеспечивается взаимодействие с функцией MessageBoxA из Win32 API, а затем используется атрибут conditional , который эквивалентен записи #if DEBUG . Если идентификатор DEBUG не определен, то и определения, и вызовы метода SayHello будут удаляться.

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >