I've created a custom tool for Visual Studio that runs your custom roslyn Syntax Walker to generate additional members. This is my way for emulating the lack of metaprogramming using roslyn in C#.
https://github.com/xiety/RoslynGenerator
For example, I've used it for generating Identity Value Types:
In AccountId.cs file:
[MetaIdentity("account")]
public partial struct AccountId : IIdentity
{
}
Assign RoslynGenerator as Custom Tool for this file, and it will generate AccountId.gen.cs file for you with some boilerplate code:
public partial struct AccountId
{
private const string Prefix = "account-";
private readonly string _value;
public AccountId(string value){ _value = value; }
public AccountId(long value)
: this(Prefix + value){}
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != typeof(AccountId)) return false;
return _value == ((AccountId)obj)._value;
}
public override string ToString() => _value;
public static implicit operator AccountId(string value) => new AccountId(value);
public static implicit operator string (AccountId id) => id._value;
public static bool operator ==(AccountId a, AccountId b) => a._value == b._value;
public static bool operator !=(AccountId a, AccountId b) => !(a == b);
public override int GetHashCode() => _value.GetHashCode();
}
To make this transformation RoslynGenerator finds in your project references class called MetaSyntaxWalker and runs it's Generate method dynamically passing SemanticModel and SyntaxRoot of current file.
Показаны сообщения с ярлыком VSIX. Показать все сообщения
Показаны сообщения с ярлыком VSIX. Показать все сообщения
вторник, 1 сентября 2015 г.
понедельник, 31 августа 2015 г.
Visual Studio Extension to run all custom tools for all solution files on every build
I've created an extension to Visual Studio that runs all custom tools on every build.
https://github.com/xiety/RunCustomToolsOnBuild
Lessons learned:
1. Make sure that "Copy local" property is set to "False" on every project reference. Or extension would not be installed. Without displaying any error messages.
2. If breakpoints do not work, you must change Project property "Include Debug Symbols in Local Deployment" to "True"
3. If you get error VSSDK1031: Extension '...' could not be found. Try to reset Exp profile and restart VS.
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /RootSuffix Exp /setup
4. Check extension files after VS project build in:
c:\users\{user}\appdata\local\microsoft\visualstudio\14.0exp\extensions\
https://github.com/xiety/RunCustomToolsOnBuild
Lessons learned:
1. Make sure that "Copy local" property is set to "False" on every project reference. Or extension would not be installed. Without displaying any error messages.
2. If breakpoints do not work, you must change Project property "Include Debug Symbols in Local Deployment" to "True"
3. If you get error VSSDK1031: Extension '...' could not be found. Try to reset Exp profile and restart VS.
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /RootSuffix Exp /setup
4. Check extension files after VS project build in:
c:\users\{user}\appdata\local\microsoft\visualstudio\14.0exp\extensions\
вторник, 9 ноября 2010 г.
C# custom tool file generation based on C# template file
Download sources and vsix from CompileGenerator.Codeplex.com
C# custom tool file generation based on C# template file. Write C# Code wich will be converted to another more detailed, specific C# code.
Features
- Build-in VS2010 .cs file Syntax highlighting and IntelliSense in template
- No need to learn new language nor syntax for template writers. C# your best friend here.
- Modifying generation code without restarting VS (code compiled in another domain)
- Code that writes code, it’s fun
- Preprocessed t4 templates for code generator
- No XML
- No more Dependency Property mess in your code
How it’s work
1. Add a new simple .cs file into your project
2. Write code that may describe some other code you need right here in your project (Dependency Properties, DTO or CQRS Commands for example)
4. Save your file and immediately get the new .cs file right in place with generated results
5. Tune your generator template and code to produce different results
C# DSL Language to describe template
Download sources and vsix from CompileGenerator.Codeplex.com
C# custom tool file generation based on C# template file. Write C# Code wich will be converted to another more detailed, specific C# code.
Features
- Build-in VS2010 .cs file Syntax highlighting and IntelliSense in template
- No need to learn new language nor syntax for template writers. C# your best friend here.
- Modifying generation code without restarting VS (code compiled in another domain)
- Code that writes code, it’s fun
- Preprocessed t4 templates for code generator
- No XML
- No more Dependency Property mess in your code
How it’s work
1. Add a new simple .cs file into your project
2. Write code that may describe some other code you need right here in your project (Dependency Properties, DTO or CQRS Commands for example)
using Xiety.DtoGenerator;
public class Nodes : DtoData
{
public void Run()
{
Namespace("Xiety.GenerationSample");
Class("TableNode", "QueryNode")
.Property("string", "TableName");
Class("OnNode")
.ListProperty("ExpressionNode", "Expressions");
Class("QueryNode", abstr: true)
.Property("QueryNode", "Query")
.Property("String", "Alias");
Class("ExpressionNode")
.Property("string", "Content");
Class("JoinNode", "QueryNode")
.Property("OnNode", "On")
.Property("QueryNode", "Left")
.Property("QueryNode", "Right");
Class("FilterNode", "QueryNode")
.Property("WhereNode", "Where");
Class("WhereNode")
.ListProperty("ExpressionNode", "Expressions");
}
}
3. Change custom tool settings of your filepublic class Nodes : DtoData
{
public void Run()
{
Namespace("Xiety.GenerationSample");
Class("TableNode", "QueryNode")
.Property("string", "TableName");
Class("OnNode")
.ListProperty("ExpressionNode", "Expressions");
Class("QueryNode", abstr: true)
.Property("QueryNode", "Query")
.Property("String", "Alias");
Class("ExpressionNode")
.Property("string", "Content");
Class("JoinNode", "QueryNode")
.Property("OnNode", "On")
.Property("QueryNode", "Left")
.Property("QueryNode", "Right");
Class("FilterNode", "QueryNode")
.Property("WhereNode", "Where");
Class("WhereNode")
.ListProperty("ExpressionNode", "Expressions");
}
}
4. Save your file and immediately get the new .cs file right in place with generated results
using System;
using System.Collections.Generic;
namespace Xiety.GenerationSample
{
public class TableNode : QueryNode
{
public string TableName { get; set; }
}
public class OnNode
{
public IList<ExpressionNode> Expressions { get; set; }
public OnNode()
{
Expressions = new List<ExpressionNode>();
}
}
public abstract class QueryNode
{
public QueryNode Query { get; set; }
public String Alias { get; set; }
}
public class ExpressionNode
{
public string Content { get; set; }
}
public class JoinNode : QueryNode
{
public OnNode On { get; set; }
public QueryNode Left { get; set; }
public QueryNode Right { get; set; }
}
public class FilterNode : QueryNode
{
public WhereNode Where { get; set; }
}
public class WhereNode
{
public IList<ExpressionNode> Expressions { get; set; }
public WhereNode()
{
Expressions = new List<ExpressionNode>();
}
}
}
using System.Collections.Generic;
namespace Xiety.GenerationSample
{
public class TableNode : QueryNode
{
public string TableName { get; set; }
}
public class OnNode
{
public IList<ExpressionNode> Expressions { get; set; }
public OnNode()
{
Expressions = new List<ExpressionNode>();
}
}
public abstract class QueryNode
{
public QueryNode Query { get; set; }
public String Alias { get; set; }
}
public class ExpressionNode
{
public string Content { get; set; }
}
public class JoinNode : QueryNode
{
public OnNode On { get; set; }
public QueryNode Left { get; set; }
public QueryNode Right { get; set; }
}
public class FilterNode : QueryNode
{
public WhereNode Where { get; set; }
}
public class WhereNode
{
public IList<ExpressionNode> Expressions { get; set; }
public WhereNode()
{
Expressions = new List<ExpressionNode>();
}
}
}
5. Tune your generator template and code to produce different results
<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
using System;
using System.Collections.Generic;
<# if (NotEmpty(Data.FileNamespace)) { #>
namespace <#= Data.FileNamespace #>
{
<# } #>
<# foreach (var cls in Data.Classes) { #>
public<#= If(cls.Abstract, " abstract") #> class <#= cls.Name #><#= IfNotNull(cls.Extends, " : {0}") #>
{
<# foreach (var property in cls.Properties) { #>
public <#= property.TypeName #> <#= property.Name #> { get; set; }
<# } #>
<# foreach (var property in cls.ListProperties) { #>
public IList<<#= property.TypeName #>> <#= property.Name #> { get; set; }
<# } #>
<# if (cls.ListProperties.Any()) { #>
public <#= cls.Name #>()
{
<# foreach (var property in cls.ListProperties) { #>
<#= property.Name #> = new List<<#= property.TypeName #>>();
<# } #>
}
<# }//constructor #>
}
<# } #>
<# if (NotEmpty(Data.FileNamespace)) { #>
}
<# } #>
<#@ import namespace="System.Linq" #>
using System;
using System.Collections.Generic;
<# if (NotEmpty(Data.FileNamespace)) { #>
namespace <#= Data.FileNamespace #>
{
<# } #>
<# foreach (var cls in Data.Classes) { #>
public<#= If(cls.Abstract, " abstract") #> class <#= cls.Name #><#= IfNotNull(cls.Extends, " : {0}") #>
{
<# foreach (var property in cls.Properties) { #>
public <#= property.TypeName #> <#= property.Name #> { get; set; }
<# } #>
<# foreach (var property in cls.ListProperties) { #>
public IList<<#= property.TypeName #>> <#= property.Name #> { get; set; }
<# } #>
<# if (cls.ListProperties.Any()) { #>
public <#= cls.Name #>()
{
<# foreach (var property in cls.ListProperties) { #>
<#= property.Name #> = new List<<#= property.TypeName #>>();
<# } #>
}
<# }//constructor #>
}
<# } #>
<# if (NotEmpty(Data.FileNamespace)) { #>
}
<# } #>
C# DSL Language to describe template
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace Xiety.DtoGenerator
{
public class DtoData
{
public string FileNamespace { get; set; }
public List<ClassNode> Classes { get; set; }
public DtoData()
{
Classes = new List<ClassNode>();
}
public void Namespace(string nspace)
{
this.FileNamespace = nspace;
}
public ClassNode Class(string name, string extends = null, bool abstr = false)
{
var cls = new ClassNode(name, extends, abstr);
this.Classes.Add(cls);
return cls;
}
}
public class ClassNode
{
public bool Abstract { get; set; }
public string Extends { get; set; }
public string Name { get; set; }
public List<PropertyNode> Properties { get; set; }
public List<ListPropertyNode> ListProperties { get; set; }
public ClassNode()
{
this.Properties = new List<PropertyNode>();
this.ListProperties = new List<ListPropertyNode>();
}
public ClassNode(string name, string extends, bool abstr)
: this()
{
this.Name = name;
this.Extends = extends;
this.Abstract = abstr;
}
public ClassNode Property(string type, string name)
{
var property = new PropertyNode(type, name);
this.Properties.Add(property);
return this;
}
public ClassNode ListProperty(string type, string name)
{
var property = new ListPropertyNode(type, name);
this.ListProperties.Add(property);
return this;
}
}
public class PropertyNode
{
public string TypeName { get; set; }
public string Name { get; set; }
public PropertyNode(string typeName, string name)
{
this.TypeName = typeName;
this.Name = name;
}
}
public class ListPropertyNode
{
public string TypeName { get; set; }
public string Name { get; set; }
public ListPropertyNode(string typeName, string name)
{
this.TypeName = typeName;
this.Name = name;
}
}
}
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace Xiety.DtoGenerator
{
public class DtoData
{
public string FileNamespace { get; set; }
public List<ClassNode> Classes { get; set; }
public DtoData()
{
Classes = new List<ClassNode>();
}
public void Namespace(string nspace)
{
this.FileNamespace = nspace;
}
public ClassNode Class(string name, string extends = null, bool abstr = false)
{
var cls = new ClassNode(name, extends, abstr);
this.Classes.Add(cls);
return cls;
}
}
public class ClassNode
{
public bool Abstract { get; set; }
public string Extends { get; set; }
public string Name { get; set; }
public List<PropertyNode> Properties { get; set; }
public List<ListPropertyNode> ListProperties { get; set; }
public ClassNode()
{
this.Properties = new List<PropertyNode>();
this.ListProperties = new List<ListPropertyNode>();
}
public ClassNode(string name, string extends, bool abstr)
: this()
{
this.Name = name;
this.Extends = extends;
this.Abstract = abstr;
}
public ClassNode Property(string type, string name)
{
var property = new PropertyNode(type, name);
this.Properties.Add(property);
return this;
}
public ClassNode ListProperty(string type, string name)
{
var property = new ListPropertyNode(type, name);
this.ListProperties.Add(property);
return this;
}
}
public class PropertyNode
{
public string TypeName { get; set; }
public string Name { get; set; }
public PropertyNode(string typeName, string name)
{
this.TypeName = typeName;
this.Name = name;
}
}
public class ListPropertyNode
{
public string TypeName { get; set; }
public string Name { get; set; }
public ListPropertyNode(string typeName, string name)
{
this.TypeName = typeName;
this.Name = name;
}
}
}
Download sources and vsix from CompileGenerator.Codeplex.com
Подписаться на:
Сообщения (Atom)