Прочитав посты из блога soumya, решил написать заметку по языку C#.
Каждые 2-3 года выходит новая версия .NET. В каждой версии придумывают новые технологии (WPF) и улучшают старые (WinForms, ASP.NET). Изменения эти значительны и требуют много времени на изучение. Синтаксис же языка C# меняется несильно.
Обычно пишут списком: что появилось в C# 2.0, 3.0 и т.д. Чтобы не копипастить материал с других сайтов, я сгруппирую его по языковым конструкциям. Примеры максимально простые, многие детали языка опущены.
Буду писать C# 1.0, при этом подразумевать реализацию этого языка в Visual Studio .NET 2003 (C# 2.0 – VS 2005, C# 3.0 - VS 2008, C# 4.0 - VS 2010).
Переменная
Именованная величина, которая может принимать различные значения.
Объявление переменной в C# 1.0:
int i = 0;
Для типов-значений в C# 2.0 можно использовать знак ‘?’:
int? i = null; //можем присвоить null
В C# 3.0 компилятор позволяет явно не указывать тип переменной, тип определяется по выражению справа от знака равенства:
var i = 0; //неявно типизированная переменная
Функция
Определяется как порция кода, выполняющая определенную задачу.
Рассмотрим возможности функций в C# 1.0:
void foo(int i, ref int j, out int k, params int[] l) { if (l.Length > 0) j = l[0]; k = 10; } int j = 5; int k; foo(10, ref j, out k, 1, 2, 3);
Ключевые слова ref и out позволяют вернуть значение в аргументе, а с помощью params можно сделать функцию с переменным числом аргументов.
В C# 3.0 появились функции-расширения. Они объявляются в одном классе, а вызываются как методы другого класса:
static class C // класс должен быть статическим { public static string foo(this int i) //статический метод и ключевое слово this { return "Мое значение: " + i; } } MessageBox.Show(10.foo()); //у типа int появилась новая функция
В C# 4.0 ввели аргументы по-умолчанию и произвольный порядок аргументов при вызове функции:
void foo(int i, int j, int k = 0) //аргументы по-умолчанию должны быть в конце {} foo(i: 10, j: 20); //аргументы идут не по порядку
Класс
Тип данных, характеризуемый своими функциями и переменными.
Самый простой класс в C# 1.0:
class C {} //нет членов класса
В C# 2.0 появились статические конструкторы:
class C { static C() {} //вызовется до первого обращения к классу }
В C# 2.0 допускается частичное объявление классов:
partial class C { int i; } partial class C //продолжение объявления того же самого типа { int j; }
В C# 3.0 можно создавать анонимные типы:
var c = new { I = 10, J = 20 }; //объект с двумя свойствами MessageBox.Show(c.J.ToString()); //свойство доступно только для чтения
Делегат
Реализует механизм обратного вызова функций. Делегаты можно передавать в параметрах функций.
Объявим делегат и функцию с параметром-делегатом:
delegate int BinaryFunction(int i, int j); void ShowBinaryFunctionInfo(BinaryFunction op, int i, int j) { MessageBox.Show(op(i, j).ToString()); }
Вызов данной функции в C# 1.0:
int Sum(int i, int j) { return i + j; } BinaryFunction op = new BinaryFunction(Sum); ShowBinaryFunctionInfo(op, 10, 20);
В C# 2.0 появились анонимные методы, позволяющие сэкономить на объявлении функции:
ShowBinaryFunctionInfo(delegate(int i, int j) { return i + j; }, 10, 20);
В C# 3.0 ввели лямбда-выражения, упрощающие анонимные методы:
ShowBinaryFunctionInfo((i, j) => { return i + j; }, 10, 20);
Свойство
Работа с объектом, как правило, осуществляется через интерфейс. Интерфейс не может содержать переменные, вместо переменных используются свойства.
Объявим интерфейс:
interface I { int Data { get; set; } //2 метода: get_Data и set_Data, они же 1 свойство }
Реализация интерфейса в C# 1.0:
class C: I { int data = 0; public int Data //реализовали свойство { get { return data; } set { Data = value; } } } I obj = new C(); obj.Data = 10; MessageBox.Show(obj.Data.ToString());
Благодаря автоматическим свойствам в C# 3.0 код сильно укорачивается:
class C: I { public int Data {get; set;} //компилятор сам пишет нужный код } I obj = new C(); obj.Data = 10; MessageBox.Show(obj.Data.ToString());
Кроме того, в C# 3.0 свойства можно инициализировать при создании объекта:
I obj1 = new C() { Data = 10 };
Обобщенное программирование
Согласно этой парадигме алгоритмы должны применяться к различным типам объектов.
Самая простая реализация этой парадигмы – использование типа object в C# 1.0:
void Swap(ref object item1, ref object item2) { object tmp = item1; item1 = item2; item2 = tmp; } object i = 10, j = 20; Swap(ref i, ref j);
В C# 2.0 ввели параметризованные классы и функции:
class C<T> //пример класса { public T data; } C<int> c = new C<int>(); c.data = 10; void Swap<T>(ref T item1, ref T item2) //пример функции { T tmp = item1; item1 = item2; item2 = tmp; } int i = 10, j = 20; Swap<int>(ref i, ref j);
В C# 4.0 допускается преобразование обобщенных типов:
delegate void Action<in T>(T item); //ключевое слово in void Display(object obj) { MessageBox.Show(obj.ToString()); } class C { } Action<C> display = Display; //аргумент функции object, а не C display(new C());
Позднее связывание
На этапе компиляции может быть неизвестно точное поведение кода. В этом случае контроль корректности вызова методов осуществляется на этапе выполнения программы.
Предварительно объявим вспомогательный класс:
class C { public int foo(int i) { return i + 1; } }
В C# 1.0 есть библиотека System.Reflection, предоставляющая информацию о типах:
Assembly a = Assembly.GetExecutingAssembly(); object obj = a.CreateInstance("WindowsFormsApplication1.C"); MethodInfo mi = obj.GetType().GetMethod("foo"); int i = (int)mi.Invoke(obj, new object[] { 0 });
В C# 4.0 данный пример можно укоротить:
Assembly a = Assembly.GetExecutingAssembly(); dynamic obj = a.CreateInstance("WindowsFormsApplication1.C"); //динамический тип int I = obj.foo(0);
Язык запросов
Предоставляет возможность поиска и манипулирования различными источниками данных.
В C# 3.0 появился встроенный язык запросов. Пример запроса для объектов в памяти:
var i1 = from c in new int[] {1,2,3} where c > 2 select c; MessageBox.Show(i1.First().ToString()); //выведет 3
Кто прочитал статью, пожалуйста, оставляйте свое мнение в комментариях.
ОтветитьУдалить