Новые возможности .NET 4.0: C# 4.0
После выхода Visual Studio 2010 beta 1 - первым делом нужно разобраться, что же дает нового нам C# 4.0 (так как это мой основной язык программирования - для меня это является важным). Первым делом должен вам порекомендовать примеры C# 4.0, которые можно скачать отсюда (там же есть документ New Features in C# 4.0, которая послужила основой для этого топика). Документацию по .Net Framework 4.0 beta 1 можно посмотреть в MSDN. Дальше будут следовать мой небольшой опыт знакомства с новой версией .NET.
1. Dynamic Language Runtime
Изначально стоит взглянуть на следующую схему, иллюстрирующую архитектуру DLR:
Именно! Теперь в .net можно еще и скриптовые языки использовать, такие как IronRuby и IronPython. Не думаю, что я буду этим пользоваться, но любителям экзотики предоставляю ссылки:
- IronPython. - open-source проект на CodePlex.
- IronRuby. - open-source проект на RubyForge.
Более того, предоставляется исходники DLR, при помощи которых вы, наверняка, сможете создать свой динамический язык для .NET, если вам это необходимо
Итак DLR включает в себя Expression Trees, которые просто являются представлением вызовов методов или бинарных операций в виде дерева, их функциональность можно посмотреть на следующем примере:
Expression<int, bool>> exprTree = num => num < 5;
// Decompose the expression tree.
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
В этом примере мы сначала описываем лямбда выражение x=>x<5, а затем при помощи объектов от Expression Trees разбираем данное выражение.
Call Site caching в DLR - это, насколько я понимаю, и есть динамическое представление вызовов методов динамических объектов или операций над динамическим объектами. DLR кеширует характеристики объектов (о типах объектах), а так же об операции, и если данная операция уже была выполнена ранее, тогда всю необходимую информацию DLR получит уже из кеша (вот как то так).
И последнее в DLR это набор классов, интерфейсов: IDynamicMetaObjectProvider, DynamicMetaObject, DynamicObject и ExpandoObject. Давайте опять посмотрим на примере, как нам это может пригодиться, и зачем нам вообще нужен этот DLR:
class Test1
{
}
static void Main(string[] args)
{
dynamic t = new Test1();
string str = t.Hello(); // Error 1
dynamic d = 7.0;
int i = d; // Error 2
}
На удивление данный код скомпилируется и запустится. Все дело в волшебном слове dynamic, оно нам позволяет вызывать любые по имени свойства или методы, а так же приводить объект к любому типу. Во время Runtime (выполнения кода) вылетят ошибки, Error 1: о том, что метод не найден, Error 2: о том, что double невозможно привести к int. Попробуем их исправить: для исправления первой ошибки наш класс Test1 отнаследуем от типа System.Dynamic.DynamicObject и перегрузим один из методов, для исправления второй просто явно укажем преобразование типов:
class Test1 : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (binder.Name == "Hello")
{
result = "Test1 is Dynamic Object!";
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
}
static void Main(string[] args)
{
dynamic t = new Test1();
string str = t.Hello();
dynamic d = 7.0;
int i = (int) d;
}
Теперь наш код будет работать. Переменная str получить значение "Test1 is dynamic object!", а i значение 7.
Конечно, необязательно наследоваться от класса DynamicObject, можно отнаследоваться и от интерфейсаIDynamicMetaObjectProvider, но тогда нужно будет самому реализовывать метод DynamicMetaObject GetMetaObject(Expression parameter), и более того реализовывать свой тип, унаследованный от DynamicMetaObject, ну в любом случае варианты есть - так что можно взять на вооружение.
2. Именованные и необязательные параметры в методах
Это достаточно простая функциональность и уже много где оговорена, она хорошо описана вот например тут (на русском языке одним из автором хабрахабра). Если парой слов, то это возможность устанавливать дефолтные значения у параметров методов, а так же возможность установки значения параметра по имени при вызове метода. В общем пример будет лучшим объяснением:
class Test1
{
public void Method(int a = 0, string b = "Hello", bool c = true)
{
Console.WriteLine("{0}, {1}, {2}", a, b, c);
}
}
static void Main(string[] args)
{
Test1 o = new Test1();
// Вызовем по как обычно
o.Method(1, "Hello", true);
// А можно поменять порядок параметров
o.Method(b: "hello", c: true, a: 1);
// Можно вообще ничего не вызывать
// (установлены значения по умолчанию у всех параметров)
o.Method();
// Можно определить только необходимые параметры
o.Method(1, "Hello");
// И не обязательно по порядку
o.Method(c: false);
}
Теперь из- за переименование параметра метода, код может и не скомпилироваться, если кто-то использовал установку значения по имени, так что нужно быть аккуратнее. Я рад дефолтным значениям, и постараюсь не использовать функциональность именованных параметров.
В дополнение хочу сказать, что если все таки будет у класса Test1 метод void Method(int a), тогда при вызове o.Method(1)вызовится именно он, а не метод из примера с дефолтными значениями.
3. Возможности для COM Interop
DLR так же дал новые возможности для COM Interop, теперь можно COM объекты определять как динамические (точнее они уже являются в большинстве своем динамического типа) и не приводить постоянно получаемые объекты к определенным типам для вызова методов или свойств.
excel.Cells[1, 1].Value = "Hello";
// вместо
((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";
Данный пример взят из документа New Futures in C# 4.0 С одной стороны приятно, что теперь не нужно мучаться и находить к какому же типу нужно привести объект, чтобы вызвать его свойство или метод, но с другой стороны теряется IntelliSense.
4. Новое в generic
Теперь обогатился и generic новой функциональностью. Можно теперь у интерфейсов и у делегатов перед определением generic типов писать out и in, зачем это чуть дальше, а сначала рассмотрим пример.
При работе с generic часто хочется сделать что то типа такого:
IList<string> strings = new List<string>();
IList<object> objects = strings;
Но нельзя. Потому, что следом можно написать:
objects[0] = 5;
string s = strings[0];
То есть, изначально у нас был список строк, потом обозначили его как список объектов, и хотим уже работать с ним, как с объектами, устанавливая любой другой объект в него, хотя список до сих пор является списком строк.
Но, если вдуматься, то можно представить, что если бы список был только для чтения, то мы бы уже не смогли ничего нарушить, и там бы логика была ясна, потому следующий код на C# 4.0 будет работать:
IEnumerable<object> objects = strings;
Огромную полезность данная функциональность принесет в работе с linq, там часто возникают проблемы, что возвращаем объекты одного типа, а нужно получить список другого типа (базового).
Итак, как же такое стало возможным. Сначала рассмотрим слово out. Теперь интерфейс IEnumerable объявлен какIEnumerable , где out обозначает, что тип T может быть использован только для возвращения значений, в другом случае компилятор будет ругаться, ну и более того это дает нам, что интерфейс IEnumerable так же есть и IEnumerable, если у A есть возможность приведения типа к B, если на простом примере, то IEnumerable , есть теперь и IEnumerable
Комментариев нет:
Отправить комментарий