Roslyn API
SyntaxTree vs CodeDom
SemanticModel vs Reflection
Денис Цветцих
АстроСофт
www.astrosoft.ru
Почему это важно
О Roslyn много говорят
• Революция в мире компиляторов
• Позволит развивать C# быстрее
• OpenSource на GitHub
• Nuget packages Microsoft.CodeAnalysis.*
Что он даст для решения прикладных задач?
• Анализ кода
• Кодогенерация
2
Почему я здесь
Решал задачу кодогенерации
• Roslyn: Syntax tree
• CodeDom
Решал задачу анализа кода
• Roslyn: Semantic model
• Reflection
3
Cравнение Roslyn с
CodeDom и Reflection
Опрос
Кто решал задачи:
• кодогенерации с помощью CodeDom?
• анализа кода с помощью Reflection?
Кто сделал хотя бы один сэмпл использования Roslyn?
Кто применял Roslyn в своих проектах?
4
План на сегодня
• Возможности Roslyn для кодогенерации и анализа кода
• Какие из них и почему мы использовали
• Сравнение Roslyn с CodeDom и Reflection
5
Какая стояла задача
Клиент для ONVIF камеры на Windows Phone 8.1
• Работа с камерой через SOAP
• Но Windows Phone 8.1 не поддерживает SOAP сервисы
6
Решение: аналог “Add Service Reference”
• Собственный класс SoapClientBase
• По WSDL генерируем код утилитой SvcUtil
• Анализируем код при помощи Reflection
• Генерируем клиент SOAP сервиса при помощи CodeDom
• Анализ кода – SemanticModel
• Генерация кода – SyntaxTree
7
Абстрактное синтактическое дерево
Абстрактное синтактическое дерево (АСД,
англ. Abstract Syntax Tree, AST) – древовидное представление
синтаксической структуры программы
Узлы – конструкции языка программирования (классы,
методы, операторы)
Листья – неделимые синтаксические конструкции
(переменные, константы, ключевые слова)
8
Пример SyntaxTree
SyntaxNode: Синий
SyntaxToken: Зеленый
SyntaxTrivia: Красный
9
Console.WriteLine("Hello World");
Создание SyntaxTree
SyntaxTree syntaxTree =
CSharpSyntaxTree.ParseText("CODE");
Важно: SyntaxTree неизменяемо
10
Решение задачи №1
• Строим AST для кода, сгенерированного SvcUtil для .NET
• Перестраиваем с учетом специфики Windows Phone 8.1
• Сохраняем код перестроенного дерева
11
CSharpSyntaxRewriter
Реализация паттерна Visitor
SyntaxVisitor.Visit(SyntaxNode node)
SyntaxNode.Accept(SyntaxVisitor visitor)
Перегрузка методов SyntaxNode Visit*
SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
12
SyntaxRewriter: заменить тип на var
1 SyntaxNode VisitLocalDeclarationStatement
2 (LocalDeclarationStatementSyntax node)
3 {
4 var declarator = node.Declaration.Variables.First();
5 TypeSyntax variableTypeName = node.Declaration.Type;
6 TypeSyntax varTypeName = SyntaxFactory.IdentifierName("var");
7 return node.ReplaceNode(variableTypeName, varTypeName);
8 }
13
Применение SyntaxRewriter
+ Незначительные точечные изменения кода
- Значительные преобразования большого объема кода
14
Решение задачи №2
• Строим AST для кода, сгенерированного SvcUtil для .NET
• Анализируем AST. Получаем:
• интерфейсы, помеченные [ServiceContract]
• классы, помеченные [DataContract]
• На основе анализа строим AST для Windows Phone 8.1
• Сохраняем код построенного дерева
15
CSharpSyntaxWalker
Тот же самый Visitor
Перегрузка методов void Visit*
void VisitClassDeclaration(ClassDeclarationSyntax node)
void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
16
Использование SyntaxWalker
1 private readonly SemanticModel _semanticModel;
2 public readonly List<INamedTypeSymbol> Services;
3
4 override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
5 {
6 var symbol = _semanticModel.GetDeclaredSymbol(node);
7 if (symbol.GetAttributes()
8 .Any(attr => attr.AttributeClass.Name == "ServiceContractAttribute"))
9 Services.Add(symbol);
10 }
17
API для кодогенерации
• Наследники SyntaxNode имеют internal конструктор
• Создание экземпляров при помощи SyntaxFactory
• Редактирование при помощи Fluent API методов With*
var decl = SyntaxFactory.ClassDeclaration("MyClass")
.WithBaseList(baseList)
.WithModifiers(modifiers)
.WithAttributeLists(attributes);
18
Создание namespace
Как реализовано
NameSyntax nameSyntax =
SyntaxFactory.ParseName("MyNamespace");
NamespaceDeclarationSyntax ns =
SyntaxFactory.NamespaceDeclaration(nameSyntax);
Как хочется
NamespaceDeclarationSyntax ns =
SyntaxFactory.NamespaceDeclaration("MyNamespace");
19
Добавление директивы using
Как реализовано
NamespaceDeclarationSyntax ns = …
var name = SyntaxFactory.ParseName("System");
var usingSyntax = SyntaxFactory.UsingDirective(name);
ns = ns.AddUsings(usingSyntax);
Как хочется
ns = ns.AddUsings("System");
20
Создание поля класса
Как реализовано
TypeSyntax type = ...
var variable = SyntaxFactory.VariableDeclarator("x");
var variableDecl = SyntaxFactory.VariableDeclaration(type);
var variableList = SyntaxFactory.SeparatedList(new[] {variable});
variableDecl = variableDecl.WithVariables(variableList);
var field = SyntaxFactory.FieldDeclaration(variableDecl);
// private int x, y, z;
// private int x;
Как хочется
var field = SyntaxFactory.FieldDeclaration("x", type);
21
Можно добавить много, нельзя один
• Переменная
• Модификатор класса, метода, свойства, …
• Реализуемые интерфейсы
22
SyntaxTree.Parse*
Преобразование строки в SyntaxNode
var body = string.Format(
"return this.CallAsync<{0}, {1}>("{2}", {3}.{4});",
v1, v2, v3, v4, v5);
SyntaxNode stmt = SyntaxFactory.ParseStatement(body);
23
Workspace
• MSBuildWorkspace – рабочая область
• Solution – набор проектов
• Project – проект, содержащий файлы исходного кода
• Document – файл исходного кода, содержит SyntaxTree и
соответствующую SemanticModel
24
Форматирование
var root = … // корень AST
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
var formattedRoot = Formatter.Format(root, workspace);
File.WriteAllText("code.cs", formattedRoot.ToFullString());
25
Syntax API для кодогенерации
• Предназначено для решения общих задач
• Добавить классу список модификаторов
• API для решения частных задач отсутствует
• Нельзя добавить классу один модификатор
• Многословно
• Создать название, а потом уже namespace
• Решение – extension методы
26
Extension метод: добавить модификатор(ы)
1 public static PropertyDeclarationSyntax WithModifiers
2 (this PropertyDeclarationSyntax propertySyntax,
3 params SyntaxKind[] modifiers)
4 {
5 var tokenList = new SyntaxTokenList();
6 foreach (var modifier in modifiers)
7 {
8 tokenList = tokenList.Add(SyntaxFactory.Token(modifier));
9 }
10 return propertySyntax.WithModifiers(tokenList);
11 } 27
SyntaxTree vs CodeDom
SyntaxTree
± Нет API для решения частных
задач (extension method)
± Сразу генерируется код на C#
+ Наличие методов Parse*
CodeDom
+ Есть API для решения частных
задач
+ Строится модель, по ней
можно сгенерить C# и VB
28
Анализ кода
Compilation – аналог проекта. Содержит:
• Список элементов для компиляции
• Assembly references
29
Создание CSharpCompilation
SyntaxTree syntaxTree =
CSharpSyntaxTree.ParseText(File.ReadAllText(csFilePath));
var mscorlib =
MetadataReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("ServiceReference",
new[] { syntaxTree },
new[] { mscorlib });
var semanticModel = compilation.GetSemanticModel(syntaxTree);
30
SemanticModel
Extension метод GetDeclaredSymbol:
по узлу SyntaxTree получить соответствующий семантический объект
IPropertySymbol GetDeclaredSymbol(PropertyDeclarationSyntax syntax)
INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax syntax)
31
Получение свойств класса
Как реализовано
ITypeSymbol typeSymbol = …
var properties = typeSymbol
.GetMembers()
.Where(m => m.Kind == SymbolKind.Property)
.Cast<IPropertySymbol>();
Как хочется
var properties = typeSymbol.GetProperties();
32
Является ли тип примитивом
Стандартной реализации нет. Можно реализовать так:
ITypeSymbol type;
var primitives = new HashSet<string>
{
"byte", "int", ext.
};
bool isPrimitive = primitives.Contains(type.ToString());
33
Анализ атрибутов
[XmlElement("elementName", typeof(Test))]
[XmlElement("elementName", Type = typeof(Test))]
public XmlElementAttribute(){}
public XmlElementAttribute(string elementName){}
public XmlElementAttribute(Type type){}
public XmlElementAttribute(string elementName, Type type){}
34
Reflection: параметр Type
var type = propertyInfo
.GetCustomAttribute<XmlElementAttribute>()
.Type;
И все! 
35
SemanticModel: AttributeData
ImmutableArray<TypedConstant>
ConstructorArguments { get; }
ImmutableArray<KeyValuePair<string, TypedConstant>>
NamedArguments { get; }
36
Ищем Type в NamedArguments
1 AttributeData attribute = … // анализируемый атрибут
2 TypedConstant? dataType; // результат
3
4 var named = attr.NamedArguments
5 .FirstOrDefault(item => item.Key == "Type");
6 if (!named.Equals(default(KeyValuePair<string, TypedConstant>)))
7 dataType = named.Value;
8 else // будем искать в параметрах конструктора
9 Продолжение на следующем слайде
37
Ищем Type в ConstructorArguments
9 if (attribute.ConstructorArguments.Length == 2)
10 dataType = attribute.ConstructorArguments.Last();
11 else
12 {
13 var arg = attribute.ConstructorArguments.FirstOrDefault();
14 if (!arg.Equals(default(TypedConstant)) &&
15 arg.Type.Name == "Type") //"Type" – System.Type
16 dataType = arg;
17 }
38
Собираем все вместе
1 AttributeData attribute = … // анализируемый атрибут
2 TypedConstant? dataType; // результат
3
4 var named = attr.NamedArguments.FirstOrDefault(item => item.Key == "Type");
5 if (!named.Equals(default(KeyValuePair<string, TypedConstant>))) dataType = named.Value;
6 else
7 if (attribute.ConstructorArguments.Length == 2)
8 dataType = attribute.ConstructorArguments.Last();
9 else {
11 var arg = attribute.ConstructorArguments.FirstOrDefault();
12 if (!arg.Equals(default(TypedConstant)) && arg.Type.Name == "Type")
13 dataType = arg;
14 }
39
SemanticModel для анализа кода
• Предназначена для решения общих задач
• Получить список членов класса
• Получить список элементов namespace
• API для решения частных задач отсутствует
• Нельзя получить отдельный список свойств класса
• Нельзя получить список классов namespace
• Нет проверки примитивности типа
• Сложная работа с атрибутами
40
Extension метод: получить свойства класса
1 public static IEnumerable<IPropertySymbol>
2 GetProperties(this ITypeSymbol typeSymbol)
3 {
4 return typeSymbol
5 .GetMembers()
6 .Where(m => m.Kind == SymbolKind.Property)
7 .Cast<IPropertySymbol>();
8 }
41
SemanticModel vs Reflection
SemanticModel
± Нет API для решения частных
задач (extension method)
- Нет проверки примитивности
типа
- Сложное получение
параметров атрибутов
Reflection
+ Есть API для решения частных
задач
+ Есть проверка примитивности
типа
+ Простое получение
параметров атрибутов
42
Впечатление от Roslyn API
Мне хотелось бы видеть Roslyn API таким, что:
• Позволяет быстро решать простые задачи
• Допускает решение сложных задач
43
Заключение
SyntaxTree
• SyntaxRewriter – для точечных изменений
• Многословность (создать имя, а потом сам namespace)
• Решает общие задачи (нельзя добавить один модификатор)
• Есть удобные методы Parse*
• Форматирование в пакете Workspace
SemanticModel
• Решает общие задачи (нельзя получить свойства класса)
• Нет проверки типа на примитивность
• Неудобная работа с атрибутами
44
Спасибо за внимание
Денис Цветцих
den.tsvettsih@yandex.ru

Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection

  • 1.
    Roslyn API SyntaxTree vsCodeDom SemanticModel vs Reflection Денис Цветцих АстроСофт www.astrosoft.ru
  • 2.
    Почему это важно ОRoslyn много говорят • Революция в мире компиляторов • Позволит развивать C# быстрее • OpenSource на GitHub • Nuget packages Microsoft.CodeAnalysis.* Что он даст для решения прикладных задач? • Анализ кода • Кодогенерация 2
  • 3.
    Почему я здесь Решалзадачу кодогенерации • Roslyn: Syntax tree • CodeDom Решал задачу анализа кода • Roslyn: Semantic model • Reflection 3 Cравнение Roslyn с CodeDom и Reflection
  • 4.
    Опрос Кто решал задачи: •кодогенерации с помощью CodeDom? • анализа кода с помощью Reflection? Кто сделал хотя бы один сэмпл использования Roslyn? Кто применял Roslyn в своих проектах? 4
  • 5.
    План на сегодня •Возможности Roslyn для кодогенерации и анализа кода • Какие из них и почему мы использовали • Сравнение Roslyn с CodeDom и Reflection 5
  • 6.
    Какая стояла задача Клиентдля ONVIF камеры на Windows Phone 8.1 • Работа с камерой через SOAP • Но Windows Phone 8.1 не поддерживает SOAP сервисы 6
  • 7.
    Решение: аналог “AddService Reference” • Собственный класс SoapClientBase • По WSDL генерируем код утилитой SvcUtil • Анализируем код при помощи Reflection • Генерируем клиент SOAP сервиса при помощи CodeDom • Анализ кода – SemanticModel • Генерация кода – SyntaxTree 7
  • 8.
    Абстрактное синтактическое дерево Абстрактноесинтактическое дерево (АСД, англ. Abstract Syntax Tree, AST) – древовидное представление синтаксической структуры программы Узлы – конструкции языка программирования (классы, методы, операторы) Листья – неделимые синтаксические конструкции (переменные, константы, ключевые слова) 8
  • 9.
    Пример SyntaxTree SyntaxNode: Синий SyntaxToken:Зеленый SyntaxTrivia: Красный 9 Console.WriteLine("Hello World");
  • 10.
    Создание SyntaxTree SyntaxTree syntaxTree= CSharpSyntaxTree.ParseText("CODE"); Важно: SyntaxTree неизменяемо 10
  • 11.
    Решение задачи №1 •Строим AST для кода, сгенерированного SvcUtil для .NET • Перестраиваем с учетом специфики Windows Phone 8.1 • Сохраняем код перестроенного дерева 11
  • 12.
    CSharpSyntaxRewriter Реализация паттерна Visitor SyntaxVisitor.Visit(SyntaxNodenode) SyntaxNode.Accept(SyntaxVisitor visitor) Перегрузка методов SyntaxNode Visit* SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) SyntaxNode VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) 12
  • 13.
    SyntaxRewriter: заменить типна var 1 SyntaxNode VisitLocalDeclarationStatement 2 (LocalDeclarationStatementSyntax node) 3 { 4 var declarator = node.Declaration.Variables.First(); 5 TypeSyntax variableTypeName = node.Declaration.Type; 6 TypeSyntax varTypeName = SyntaxFactory.IdentifierName("var"); 7 return node.ReplaceNode(variableTypeName, varTypeName); 8 } 13
  • 14.
    Применение SyntaxRewriter + Незначительныеточечные изменения кода - Значительные преобразования большого объема кода 14
  • 15.
    Решение задачи №2 •Строим AST для кода, сгенерированного SvcUtil для .NET • Анализируем AST. Получаем: • интерфейсы, помеченные [ServiceContract] • классы, помеченные [DataContract] • На основе анализа строим AST для Windows Phone 8.1 • Сохраняем код построенного дерева 15
  • 16.
    CSharpSyntaxWalker Тот же самыйVisitor Перегрузка методов void Visit* void VisitClassDeclaration(ClassDeclarationSyntax node) void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) 16
  • 17.
    Использование SyntaxWalker 1 privatereadonly SemanticModel _semanticModel; 2 public readonly List<INamedTypeSymbol> Services; 3 4 override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) 5 { 6 var symbol = _semanticModel.GetDeclaredSymbol(node); 7 if (symbol.GetAttributes() 8 .Any(attr => attr.AttributeClass.Name == "ServiceContractAttribute")) 9 Services.Add(symbol); 10 } 17
  • 18.
    API для кодогенерации •Наследники SyntaxNode имеют internal конструктор • Создание экземпляров при помощи SyntaxFactory • Редактирование при помощи Fluent API методов With* var decl = SyntaxFactory.ClassDeclaration("MyClass") .WithBaseList(baseList) .WithModifiers(modifiers) .WithAttributeLists(attributes); 18
  • 19.
    Создание namespace Как реализовано NameSyntaxnameSyntax = SyntaxFactory.ParseName("MyNamespace"); NamespaceDeclarationSyntax ns = SyntaxFactory.NamespaceDeclaration(nameSyntax); Как хочется NamespaceDeclarationSyntax ns = SyntaxFactory.NamespaceDeclaration("MyNamespace"); 19
  • 20.
    Добавление директивы using Какреализовано NamespaceDeclarationSyntax ns = … var name = SyntaxFactory.ParseName("System"); var usingSyntax = SyntaxFactory.UsingDirective(name); ns = ns.AddUsings(usingSyntax); Как хочется ns = ns.AddUsings("System"); 20
  • 21.
    Создание поля класса Какреализовано TypeSyntax type = ... var variable = SyntaxFactory.VariableDeclarator("x"); var variableDecl = SyntaxFactory.VariableDeclaration(type); var variableList = SyntaxFactory.SeparatedList(new[] {variable}); variableDecl = variableDecl.WithVariables(variableList); var field = SyntaxFactory.FieldDeclaration(variableDecl); // private int x, y, z; // private int x; Как хочется var field = SyntaxFactory.FieldDeclaration("x", type); 21
  • 22.
    Можно добавить много,нельзя один • Переменная • Модификатор класса, метода, свойства, … • Реализуемые интерфейсы 22
  • 23.
    SyntaxTree.Parse* Преобразование строки вSyntaxNode var body = string.Format( "return this.CallAsync<{0}, {1}>("{2}", {3}.{4});", v1, v2, v3, v4, v5); SyntaxNode stmt = SyntaxFactory.ParseStatement(body); 23
  • 24.
    Workspace • MSBuildWorkspace –рабочая область • Solution – набор проектов • Project – проект, содержащий файлы исходного кода • Document – файл исходного кода, содержит SyntaxTree и соответствующую SemanticModel 24
  • 25.
    Форматирование var root =… // корень AST MSBuildWorkspace workspace = MSBuildWorkspace.Create(); var formattedRoot = Formatter.Format(root, workspace); File.WriteAllText("code.cs", formattedRoot.ToFullString()); 25
  • 26.
    Syntax API длякодогенерации • Предназначено для решения общих задач • Добавить классу список модификаторов • API для решения частных задач отсутствует • Нельзя добавить классу один модификатор • Многословно • Создать название, а потом уже namespace • Решение – extension методы 26
  • 27.
    Extension метод: добавитьмодификатор(ы) 1 public static PropertyDeclarationSyntax WithModifiers 2 (this PropertyDeclarationSyntax propertySyntax, 3 params SyntaxKind[] modifiers) 4 { 5 var tokenList = new SyntaxTokenList(); 6 foreach (var modifier in modifiers) 7 { 8 tokenList = tokenList.Add(SyntaxFactory.Token(modifier)); 9 } 10 return propertySyntax.WithModifiers(tokenList); 11 } 27
  • 28.
    SyntaxTree vs CodeDom SyntaxTree ±Нет API для решения частных задач (extension method) ± Сразу генерируется код на C# + Наличие методов Parse* CodeDom + Есть API для решения частных задач + Строится модель, по ней можно сгенерить C# и VB 28
  • 29.
    Анализ кода Compilation –аналог проекта. Содержит: • Список элементов для компиляции • Assembly references 29
  • 30.
    Создание CSharpCompilation SyntaxTree syntaxTree= CSharpSyntaxTree.ParseText(File.ReadAllText(csFilePath)); var mscorlib = MetadataReference.CreateFromAssembly(typeof(object).Assembly); var compilation = CSharpCompilation.Create("ServiceReference", new[] { syntaxTree }, new[] { mscorlib }); var semanticModel = compilation.GetSemanticModel(syntaxTree); 30
  • 31.
    SemanticModel Extension метод GetDeclaredSymbol: поузлу SyntaxTree получить соответствующий семантический объект IPropertySymbol GetDeclaredSymbol(PropertyDeclarationSyntax syntax) INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax syntax) 31
  • 32.
    Получение свойств класса Какреализовано ITypeSymbol typeSymbol = … var properties = typeSymbol .GetMembers() .Where(m => m.Kind == SymbolKind.Property) .Cast<IPropertySymbol>(); Как хочется var properties = typeSymbol.GetProperties(); 32
  • 33.
    Является ли типпримитивом Стандартной реализации нет. Можно реализовать так: ITypeSymbol type; var primitives = new HashSet<string> { "byte", "int", ext. }; bool isPrimitive = primitives.Contains(type.ToString()); 33
  • 34.
    Анализ атрибутов [XmlElement("elementName", typeof(Test))] [XmlElement("elementName",Type = typeof(Test))] public XmlElementAttribute(){} public XmlElementAttribute(string elementName){} public XmlElementAttribute(Type type){} public XmlElementAttribute(string elementName, Type type){} 34
  • 35.
    Reflection: параметр Type vartype = propertyInfo .GetCustomAttribute<XmlElementAttribute>() .Type; И все!  35
  • 36.
    SemanticModel: AttributeData ImmutableArray<TypedConstant> ConstructorArguments {get; } ImmutableArray<KeyValuePair<string, TypedConstant>> NamedArguments { get; } 36
  • 37.
    Ищем Type вNamedArguments 1 AttributeData attribute = … // анализируемый атрибут 2 TypedConstant? dataType; // результат 3 4 var named = attr.NamedArguments 5 .FirstOrDefault(item => item.Key == "Type"); 6 if (!named.Equals(default(KeyValuePair<string, TypedConstant>))) 7 dataType = named.Value; 8 else // будем искать в параметрах конструктора 9 Продолжение на следующем слайде 37
  • 38.
    Ищем Type вConstructorArguments 9 if (attribute.ConstructorArguments.Length == 2) 10 dataType = attribute.ConstructorArguments.Last(); 11 else 12 { 13 var arg = attribute.ConstructorArguments.FirstOrDefault(); 14 if (!arg.Equals(default(TypedConstant)) && 15 arg.Type.Name == "Type") //"Type" – System.Type 16 dataType = arg; 17 } 38
  • 39.
    Собираем все вместе 1AttributeData attribute = … // анализируемый атрибут 2 TypedConstant? dataType; // результат 3 4 var named = attr.NamedArguments.FirstOrDefault(item => item.Key == "Type"); 5 if (!named.Equals(default(KeyValuePair<string, TypedConstant>))) dataType = named.Value; 6 else 7 if (attribute.ConstructorArguments.Length == 2) 8 dataType = attribute.ConstructorArguments.Last(); 9 else { 11 var arg = attribute.ConstructorArguments.FirstOrDefault(); 12 if (!arg.Equals(default(TypedConstant)) && arg.Type.Name == "Type") 13 dataType = arg; 14 } 39
  • 40.
    SemanticModel для анализакода • Предназначена для решения общих задач • Получить список членов класса • Получить список элементов namespace • API для решения частных задач отсутствует • Нельзя получить отдельный список свойств класса • Нельзя получить список классов namespace • Нет проверки примитивности типа • Сложная работа с атрибутами 40
  • 41.
    Extension метод: получитьсвойства класса 1 public static IEnumerable<IPropertySymbol> 2 GetProperties(this ITypeSymbol typeSymbol) 3 { 4 return typeSymbol 5 .GetMembers() 6 .Where(m => m.Kind == SymbolKind.Property) 7 .Cast<IPropertySymbol>(); 8 } 41
  • 42.
    SemanticModel vs Reflection SemanticModel ±Нет API для решения частных задач (extension method) - Нет проверки примитивности типа - Сложное получение параметров атрибутов Reflection + Есть API для решения частных задач + Есть проверка примитивности типа + Простое получение параметров атрибутов 42
  • 43.
    Впечатление от RoslynAPI Мне хотелось бы видеть Roslyn API таким, что: • Позволяет быстро решать простые задачи • Допускает решение сложных задач 43
  • 44.
    Заключение SyntaxTree • SyntaxRewriter –для точечных изменений • Многословность (создать имя, а потом сам namespace) • Решает общие задачи (нельзя добавить один модификатор) • Есть удобные методы Parse* • Форматирование в пакете Workspace SemanticModel • Решает общие задачи (нельзя получить свойства класса) • Нет проверки типа на примитивность • Неудобная работа с атрибутами 44
  • 45.
    Спасибо за внимание ДенисЦветцих den.tsvettsih@yandex.ru

Editor's Notes

  • #3 О Roslyn много говорят, отзывы положительные. Да, он поможет быстрее развивать C#. Кроме прочего, код Roslyn открыт, и его функционал поставляется в виде пакетов. Но что он даст широкому кругу разработчиков для решения прикладных задач, например кодогенерации и анализа кода Это не такие распространенные задачи, как разработка справочников, но все же они боле актуальны, чем прикручивание новых фичей к C#
  • #4 Я – послание, Я проходил через, я научился, я хочу чтобы вы
  • #5 Кто решал задачи: для вас этот доклад может оказаться полезным, потому, что вы узнаете что-то новое. Вы увидите, как те же самые задачи можно решить с помощью другого инструмента. У вас расширится кругозор. И в следующий раз вы можете применить Roslyn для решения тех же задач. Кто сделал сэмпл: я расскажу о нашем опыте и о тех граблях, которые мы собрали., чтобы вы на них уже не наступили У кого реальный опыт: мы можем обменяться опытом, а возможно вы даже чем-то меня дополните.
  • #7 Так ребята из MS ненавязчиво намекают, что SOAP – это не тренд. Особенно при разработке мобильных приложений. Проблема: в фреймворке нет API, которое нужно для решения нашей задачи
  • #8 Картинка?
  • #9 Для других языков уже было реализовано. Например для питона и Java. Сейчас есть и для C#
  • #11 Сказать про неизменяемость синтаксического дерева. Это позволяет одновременно анализировать синтаксическое дерево несколькими потоками
  • #13 Позволяет решать простые задачи, вносить точечные правки Пример – заменить имена классов в объявлении переменных на var Для ситуации, когда код приходится перефигачивать очень сильно, он не подходит
  • #17 Просто обход дерева без его изменения. Пример – выбор дата контрактов и ServiceContract
  • #20 Возможно стоит заменить на названия типов на var, чтобы влезало в одну строку
  • #21 Возможно стоит заменить на названия типов на var, чтобы влезало в одну строку
  • #22 Пример достаточно показателен. Нельзя добавить классу один модификатор. Их можно добавить несколько. Нельзя добавить один базовый класс, их можно добавить несколько. Нужны ли примеры базовых классов и модификаторов
  • #25 Полезно для разработчиков плагинов к студии. Но содержит полезную для кодогенерации фичу – форматирование. Мы её как-то не сразу нашли, поэтому я о ней говорю, чтобы вы о ней знали и могли использовать.
  • #40 Этот код не надо читать, здесь весь пример собран воедино Кода много, и он сложный. Самое плохое – он подходит только для атрибута XmlElement. Для другого атрибута этот код придется переписывать. А если атрибуту добавить или удалить конструкторов, этот код сломается.
  • #44 Колбаса нравится не только из-за вкуса, но и из-за того, насколько хорошо она чистится.
  • #46 Надеюсь, этот доклад оказался для вас полезным, и породил у вас какие-то практические мысли. Если у вас есть какие-то вопросы, буду рад на них ответить Принцип 48 часов: чтобы информация не забылась, нужно что-то сделать. Поиграйтесь с 2015 студией, попробуйте визуализировать SyntaxTree для вашего кода Скачайте и посмотрите сэмплы, напишите простейший пример использовани Roslyn: как поменять название типа на var Занесите Issue в GitHub. Сами их реализуйте, сделайте Pull Request докажите насколько вы крутой программист.