Краткий пересказ
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.09.05 16:24
Оценка: 400 (43) +1
В качестве основной цели задекларированна поддержка функционального стиля.
1) Неявно типизированные локальные переменные (implicitly typed local variable). То о чем долго говорили большевики в форуме философия. Даже ключевое слово народ там угадал. Пример:
var i = 5;
var s = "Hello";
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary<int,Order>();

var x;                    // Error, no initializer to infer type from
var y = {1, 2, 3};    // Error, collection initializer not permitted
var z = null;            // Error, null type not permitted

int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);

Зачем это нужно, надеюсь понятно.

2) Расширяющие методы (Extension methods). Хитрая штука. Позволяет объявлять статические методы с параметром this и привязывать их в качестве метода экземпляра к существующим классам.
Объявляются такие методы как обычные, но перед первым параметром добавляется модификатор this.
namespace Acme.Utilities
{
    public static class Extensions
    {
        public static int ToInt32(this string s) {
            return Int32.Parse(s);
        }
        public static T[] Slice<T>(this T[] source, int index, int count) {
            if (index < 0 || count < 0 || source.Length – index < count)
                throw new ArgumentException();
            T[] result = new T[count];
            Array.Copy(source, index, result, 0, count);
            return result;
        }
    }
}

Использовать это очень просто — достаточно написать using на соотв. неймспейс.
using Acme.Utilities;

...

string s = "1234";
int i = s.ToInt32();                    // Same as Extensions.ToInt32(s)
int[] digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] a = digits.Slice(4, 3);        // Same as Extensions.Slice(digits, 4, 3)

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

3) Лямбда-выражения. Выражения, служащие для написания программ в функциональном стиле. Вобщем то в 2.0 анонимные методы очень на это похожи, но в 3.0 сделана попытка преобразовать внешний вид к более функциональному стилю. Для этого введен новый токен — =>.
Пример:
delegate R Func<A,R>(A arg);

...

Func<int,int> f1 = x => x + 1;            // Ok
Func<int,double> f2 = x => x + 1;        // Ok
Func<double,int> f3 = x => x + 1;        // Error

Любители функционального стиля будут довольны. Хотя возможность творить на этой базе извраты (особенно если совместно с дженериками) меня пугает.

4) Инициализаторы объектов и коллекций (Object and collection initializers). Позволяют в одном выражении вызвать конструктор и присвоить ряд значений. Сахарок для улучшения читаемости кода.
Примеры:
var a = new Point { X = 0, Y = 1 };
// which has the same effect as
// var a = new Point();
// a.X = 0;
// a.Y = 1;

var r = new Rectangle {
    P1 = new Point { X = 0, Y = 1 },
    P2 = new Point { X = 2, Y = 3 }
};
// which has the same effect as
// var r = new Rectangle();
// var __p1 = new Point();
// __p1.X = 0;
// __p1.Y = 1;
// r.P1 = __p1;
// var __p2 = new Point();
// __p2.X = 2;
// __p2.Y = 3;
// r.P2 = __p2;

var contacts = new List<Contact> {
    new Contact {
        Name = "Chris Smith",
        PhoneNumbers = { "206-555-0101", "425-882-8080" }
    },
    new Contact {
        Name = "Bob Harris",
        PhoneNumbers = { "650-555-0199" }
    }
};
// which has the same effect as
// var contacts = new List<Contact>();
// var __c1 = new Contact();
// __c1.Name = "Chris Smith";
// __c1.PhoneNumbers.Add("206-555-0101");
// __c1.PhoneNumbers.Add("425-882-8080");
// contacts.Add(__c1);
// var __c2 = new Contact();
// __c2.Name = "Bob Harris";
// __c2.PhoneNumbers.Add("650-555-0199");
// contacts.Add(__c2);

Не уверен, но по идее должно работать и так:
var dict = new Dictionary<string, int> {
    new KeyValuePair<string, int>("one", 1),
    new KeyValuePair<string, int>("two", 2),
    new KeyValuePair<string, int>("three", 3)
}


5. Анонимные типы. Проистекают из возможностей в п.1 и п.4. На основании объектного инициализатора выводится тип.
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2;
// Компилятор неявно создает следующий класс:
// class __Anonymous1
{
    private string _name;
    private double _price;
    
    public string Name { get {return _name;} set {_name = value;}}
    public double Price { get {return _price;} set {_price = value;}}
}

Прикольно. К сожалению, если я правильно понял, использовать такие типы без рефлекшена или делегатов можно только внутри одного метода.

6. Неявно типизированные массивы. Тоже сахарок, позволяющий не указыватьв new тип массива.
var a = new[] { 1, 10, 100, 1000 };                // int[]
var b = new[] { 1, 1.5, 2, 2.5 };                // double[]
var c = new[] { "hello", null, "world” };        // string[]
var d = new[] { 1, "one", 2, "two" };            // Error


7. Выражения запроса. (Query expressions). В новый язык добавлены декларативные конструкции, похожие на SQL.
Можно писать так:
from c in customers
where c.City == "London"
from o in c.Orders
where o.OrderDate.Year == 2005
select new { c.Name, o.OrderID, o.Total }

Компилятор это оттранслирует в такое:
customers.
Where(c => c.City == "London").
SelectMany(c =>
    c.Orders.
    Where(o => o.OrderDate.Year == 2005).
    Select(o => new { c.Name, o.OrderID, o.Total })
)

Класс, для которого разрешены такие фокусы, должен выглядеть примерно так:
delegate R Func<A,R>(A arg);
class C<T>
{
    public C<T> Where(Func<T,bool> predicate);
    public C<S> Select<S>(Func<T,S> selector);
    public C<S> SelectMany<S>(Func<T,C<S>> selector);
    public O<T> OrderBy<K>(Func<T,K> keyExpr);
    public O<T> OrderByDescending<K>(Func<T,K> keyExpr);
    public C<G<K,T>> GroupBy<K>(Func<T,K> keyExpr);
    public C<G<K,E>> GroupBy<K,E>(Func<T,K> keyExpr, Func<T,E> elemExpr);
}
class O<T> : C<T>
{
    public O<T> ThenBy<K>(Func<T,K> keySelector);
    public O<T> ThenByDescending<K>(Func<T,K> keySelector);
}
class G<K,T>
{
    public K Key { get; }
    public C<T> Group { get; }
}

ИМХО изврат редкостный. Насколько это будет полезно я пока ответить затрудняюсь.

8. Дерево выражений. Лямбда-выражения преобразуются компилятором в анонимные методы. Однако есть возможность сохранять эти самые выражения ввиде структуры с данными, которые умеют потом, в рантайме, при помощи эмита генерить эти самые методы:
Func<int,int> f = x => x + 1;                        // Code
Expression<Func<int,int>> e = x => x + 1;        // Data

Зачем это нужно пока не сказано. Все что есть:

Expression trees are efficient in-memory data representations of lambda expressions and make the structure of the expression transparent and explicit.

Вот так — прозрачные и явные. Попой чую, что для каких то особо хитрых извратств в рантайме (скорее всего связанных с п.7), но чего то вечером пример придумать не могу. Ну разве что такую лямбду можно будет сериализовать (к примеру, чтобы сохранить в БД или передать по сети).
... << RSDN@Home 1.2.0 alpha rev. 617>>
AVK Blog
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.