Monday, April 21, 2014

Обзор The Future of C# - Build 2014

В этой статье я рассмотрю, какие новые возможности нам принесет новый C# 6.0. За основу взято видео выступлений Mads Torgersen и Dustin Cambell Program Mangers компании Майкрософт, на конференции Build 2014, на которой они представили доклад "The Future of C#". Я уже писал о новых возможностях языка C# в статье "Возможности C# 6.0", часть информации для данной той статьи взята с источников и блогов, которые посвящены презентациям конференции NDC 2013 (New Developers Conference), проходившей с 2 по 6 декабря в Лондоне. Эту же информацию, взятую с Build 2014, можно считать практически окончательной. Вероятно, язык C# до релиза не получит значительных изменений. 
Всю презентацию о возможностях языка C#, представленную на данной конференции, можно условно поделить на две части: одну часть представлял Dustin Cambell, который рассказывал о возможностях проекта Roslyn (компилятор как сервис), вторая часть являла собой доклад Mads Torgersen, который представил новые фишки, доступные разработчикам. Думаю, что смогу дополнить статью, написанную раньше примером, который продемонстрировал Torgersen
Пройдемся по первой части презентации, на которой были продемонстрированы возможности Roslyn. Поскольку я уже до этого частично был знаком с Roslyn (Введение в Roslyn – статья о проекте Roslyn), то мне эта тема была особенно интересна. Одна из основных позитивных новостей заключается в том, что  Roslyn стал open-source, и вы можете скачать исходники с домашней страницы – .NET Compiler Platform ("Roslyn"). Вторая новость также очень радостная: он наконец-то обновился. Последняя актуальная версия, с которой можно было работать, была выпущенная CTP (Community Technology Preview) версия Roslyn, точнее, ее обновление, которое было доступно с сентября 2012 года. В той версии не работали такие возможности языка C#, как dynamic, async/await, task, lambda expression и другие. Теперь все это работает и доступно для использования. Вы можете скачать Roslyn через NuGet либо клонировать себе проект с Git репозитория с домашней страницы данного проекта.
Теперь расскажу любителям данного проекта о некоторых особенностях, по сравнению с предыдущей CTP версией. Эти наблюдения я сделал с видео презентации, часть которой представлял Cambell о Roslyn, а также на своем опыте с этим проектом. Первое? что бросается в глаза, – что проект изменился незначительно. Я бы даже сказал, что он стал проще. Теперь у нас доступен меньший список шаблонов для проектов, которые предоставляет Roslyn. Предыдущая CTP версия для Visual Studio 2012 выглядела так:
И шаблоны Roslyn проектов для Visual Studio 2013, которые были представлены:
Их стало поменьше. Я постараюсь плотно поработать с новым Roslyn и выложить статью о том, что же, все-таки, изменилось в нем, более детально для Visual Studio 2012. Интересный момент: на Roslyn за 15 минут презентации был написан рабочий пример, который позволял поставить скобки вокруг условия if
Хочу уделить больше внимания именно второй части выступления, в которой были представлены новые возможности языка C#. Одна из возможностей, которую назвал Torgersen, – это работа с Case в VB (из упоминания в данном контексте C# я предполагаю, что подобное поведение будет работать и в данном языке).
Другая возможность, которая была представлена для VB.NET, была binary literal.
<Flags>
Enum RestaurantFeatures3
    IsOpenBreakfast     = &B0000_0001
    IsOpenLunch         = &B0000_0010
    IsOpenDinner        = &B0000_0100
    IsOpen24Hours       = &B0000_1000
    IsOpenWeekends      = &B0001_0000

    HasDelivery         = &B0010_0000
    HasTakeOut          = &B0100_0000
End Enum
Неплохая возможность языка, если она будет работать в C#, а так судить об этой возможности могут разработчики, которые плотно работают с VB.NET. Данные будет представлены 32-битным целым значением.
Первым, что продемонстрировал Torgersen по языку C# на примере работы с Json, был пример с использованием using для статических типов. Пример:
До:
static void Main(string[] args)
{
    Console.WriteLine("Hello World");
}
После:
using System.Console;
static void Main(string[] args)
{
    WriteLine("Hello World");
}
Правда, эта возможность уже была показана раньше на NDC 2013, ее просто продемонстрировали вживую еще раз. Для следующей демонстрации я набросал подобный пример, который был продемонстрирован на демонстрации, и буду показывать все на нем. Еще один важный момент, который использовался на презентации, – это использование библиотеки Json.Net.
Мы будем использовать такую же возможность, как в демонстрации. 
P.S. К сожалению, возможность посмотреть новые фишки языка C# пока недоступны для простых смертных, об этом сказал Torgersen. Он также заметил, что у него Preview версия Visual Studio, на которой он пробовал новые возможности языка, так что, думаю, в скором времени мы с вам сможем насладиться новым синтаксисом языка C# 6.0 более подробно.  Пример кода приведен ниже.
class Program
{
    static void Main(string[] args)
    {
        var points = new[] {new Point(1, 2), new Point(-1, 3), new Point(4, 5)};
        var json = Point.ToJson(points);
        var getPoints = Point.FromJson(json).ToList();
        Console.ReadLine();
    }
}

public class Point
{
    private int _x;
    private int _y;

    public Point(int x, int y)
    {
        _x = x;
        _y = y;
    }

    public int X { get { return _x; } }
    public int Y { get { return _y; } }

    public double Dist { get { return Math.Sqrt(X*X + Y*Y); } }

    public static JArray ToJson(IEnumerable<Point> points)
    {
        var result = new JArray();
        foreach (var point in points)
        {
            if(point == null) continue;
            var json = new JObject();
            json["x"] = point.X;
            json["y"] = point.Y;
            result.Add(json);
        }
        return result;
    }
    public static IEnumerable<Point> FromJson(JArray array)
    {
        foreach (var json in array)
        {
            if(json == null) continue;
            int x, y;
            if(TryGetInt(json["x"], out x) && TryGetInt(json["y"], out y))
                yield return new Point(x, y);
        }
    }

    private static bool TryGetInt(JToken json, out int value)
    {
        return Int32.TryParse(json.ToString(), out value);
    }
}
Были продемонстрированы не все функции, поэтому часть кода я написал сам. Воспользуемся конструктором по умолчанию, который будет доступен в новом C#.
До нововведения:
private int _x;
private int _y;

public Point(int x, int y)
{
    _x = x;
    _y = y;
}
После нововведения:
public class Point(int x, int y)
{
    private int _x = x;
    private int _y = y;
После этого воспользуемся новым синтаксисом properties,  для того чтобы немного модифицировать наш код.
До нововведения:
public class Point
{
    private int _x;
    private int _y;

    public Point(int x, int y)
    {
        _x = x;
        _y = y;
    }

    public int X { get { return _x; } }
    public int Y { get { return _y; } }

После нововведения:
public class Point(int x, int y)
{
    private int _y = y;

    public int X { get; } = x ;
    public int Y { get { return _y; } }
Интересная возможность нового C#: задание модификатора доступа через параметр.
До нововведения:
public class Point
{
    private readonly int _x;
    private readonly int _y;

    public Point(int x, int y)
    {
        _x = x;
        _y = y;
    }

    public int X { get { return _x; } }
    public int Y { get { return _y; } }
После нововведения:
public class Point(int x, private readonly int y)
{
    public int X { get; } = x ;
    public int Y { get { return +y; } }
Если вы обратите внимание, то возле нашего параметра стоит знак "+". В коде ниже изменения подчеркнуто красным.
public int Y { get { return +y; } }
Об использовании using для статических методов мы уже не упоминали с самого начала, когда начали обсуждать новшества C#. А сейчас рассмотрим такую возможность, как property expression. Эту возможность в докладе Torgersen упомянул лишь вскользь, но это не мешает нам рассмотреть ее более подробно.
До нововведения:
public double Dist { get { return Math.Sqrt(X * X + Y * Y); } }
После нововведения:
using System.Math ;
public double Dist => Sqrt(X * X + Y * Y);
Следующей рассмотрим возможность работы со строковыми ключами словарей.  
До нововведения:
public static JArray ToJson(IEnumerable<Point> points)
{
    var result = new JArray();
    foreach (var point in points)
    {
        if (point == null) continue;
        var json = new JObject();
        json["x"] = point.X;
        json["y"] = point.Y;
        result.Add(json);
    }
    return result;
}
Нас будет интересовать только часть
var json = new JObject();
json["x"] = point.X;
json["y"] = point.Y;
После нововведения:
var json = new JObject { ["x"] = point.X, ["y"] = point.Y };
Весь пример будет выглядеть так:
public static JArray ToJson(IEnumerable<Point> points)
{
    var result = new JArray();
    foreach (var point in points)
    {
        if (point == null) continue;
        var json = new JObject { ["x"] = point.X, ["y"] = point.Y };
        result.Add(json);
    }
    return result;
}
И вторая возможность с помощью синтаксического сахара  символа $. Вот как будет выглядеть измененный пример:
public static JArray ToJson(IEnumerable<Point> points)
{
    var result = new JArray();
    foreach (var point in points)
    {
        if (point == null) continue;
        var json = new JObject { $x = point.X, $y = point.Y };
        result.Add(json);
    }
    return result;
}
Изменения выделены красным ниже
var json = new JObject { $x = point.X, $y = point.Y };
Но больше всего мне понравилось передавать коллекцию для инициализации с помощью linq expression с учетом рассмотренных последних новых возможностей языка C#.
public static JArray ToJson(IEnumerable<Point> points)
    {
       return new JArray(
            from p in points
            where p != null
            select new JObject { $x = point.X, $y = point.Y }
            );
    }
Теперь рассмотрим, как использовать "синтаксический сахар" (оператор $) вместо постоянного обращения ["x"], ["y"].
До нововведения:
public static IEnumerable<Point> FromJson(JArray array)
{
    foreach (var json in array)
    {
        if (json == null) continue;
        int x, y;
        if (TryGetInt(json["x"], out x) && TryGetInt(json["y"], out y))
            yield return new Point(x, y);
    }
}
После нововведения:
public static IEnumerable<Point> FromJson(JArray array)
{
    foreach (var json in array)
    {
        if (json == null) continue;
        int x, y;
        if (TryGetInt(json.$x, out x) && TryGetInt(json.$y, out y))
            yield return new Point(x, y);
    }
}
Следующим моментом мы рассмотрим встроенное объявление для входных параметров.
До нововведения:
int x, y;
if (TryGetInt(json["x"], out x) && TryGetInt(json["y"], out y))
После нововведения:
if (TryGetInt(json["x"], out int x) && TryGetInt(json["y"], out int y))
Полный пример – ниже.
public static IEnumerable<Point> FromJson(JArray array)
{
    foreach (var json in array)
    {
        if (json == null) continue;
        if (TryGetInt(json["x"], out int x) && TryGetInt(json["y"], out int y))
            yield return new Point(x, y);
    }
}
Но более интересен тот момент, что встроенное объявление можно задать через var. Поскольку в нашей функции TryGetInt явно задан параметр int,
private static bool TryGetInt(JToken json, out int value)
{
    return Int32.TryParse(json.ToString(), out value);
}
мы можем приведенный выше пример переписать так:
public static IEnumerable<Point> FromJson(JArray array)
{
    foreach (var json in array)
    {
        if (json == null) continue;
        if (TryGetInt(json["x"], out var x) && TryGetInt(json["y"], out var y))
            yield return new Point(x, y);
    }
}
Следующим моментом, который был затронут,  это возможность нормально обрабатывать await в try-finally. Сам Torgersen не привел пример, как это использовать, но я предполагаю, что это будет выглядеть как-то так:
До нововведения:
var client = new WebClient();
await client.DownloadDataTaskAsync(new Uri("https://www.google.com.ua"));
После нововведения:
public async void ReadData()
{
    var client = new WebClient();

    try
    {
        await client.DownloadDataTaskAsync(new Uri("https://www.google.com.ua"));
    }
    catch
    {
        Console.WriteLine("Catch block");
    }
    finally
    {
        Console.WriteLine("Finish");
    }
       
}

И этот код должен отрабатывать корректно, и мы сможем нормально обрабатывать наши асинхронные операции. Также в новой версии языка C# будут добавлено exception filters. Что это собой представляет, к сожалению, не знаю, могу только судить оп названию, но надеюсь в скором времени мы с вами все узнаем, что это такое. На этом заканчиваю краткий доклад о новых возможностях языка C#, которые мне поведали Torgersen и Cambell. Если у вас нет проблем с английским, то полную версию доклада вы можете посмотреть по ссылке на channel9: "The Future of C#".

No comments:

Post a Comment