前段时间我发布了 github开源:企业级应用快速开发框架CIIP WEB+WIN+移动端,很多园友们都表示支持并与我探讨相关技术问题,上篇中我也承诺会写相关的技术文章,本篇就来介绍一下建模模块中使用的动态编译技术。


那些年我们用过的动态编译技术

说是动态编译技术有些片面,因为在框架中,具体应用到的是建模模块,在CIIP中,使用的是xpo的orm,基于XAF开发,而在XAF中建模过程就是以codefirst(多数人喜爱的)方式写BusinessObject(BO、Entity)的过程。所以建模的过程多数工作就变成了组装出BusinessObject的过程了。

在CIIP中,尝试过下面列出的2,3,4的方式:

1.CodeDom,这个比较老了,TA看起来是Roslyn的语法树的子级,但看起来挺麻烦的,所以我没有用这个。

2.Reflection.Emit,使用.net提供的运行时以emit il的方式生成方法(Method),定义程序集、定义模块、定义类、定义接口等都比较容易,这个方式我从头到尾的应用过,在CIIP中,需要从头到尾的生成类,类有很多复杂情况,Reflection.Emit是处理不了的,比如说泛型的循环引用。

public class 单据基类<单据明细>
{ } public class 单据明细<单据基类>
{ } public class 订单:单据基类<订单明细>
{ } public class 订单明细:单据明细<订单>
{ }

比如上面的代码,当然还有构造函数,生成就是有问题的。我查询了 装配脑袋 的早期博文,在解析程序集、类,时再去调用CreateType,对于他举出的例子中是可用的,但在上述情景下,是不能用的,这个比他的例子还要复杂些。

3.Mono.Cecil,这个是Mono下面的开源项目,动态生成程序集、做dll级别的重构、生成动态程序集,做得很不错。这个也曾经大规模使用于项目中,最后放弃了,原因有点记不清了.

4.Roslyn,这个是微软自己的开源项目,项目地址:https://github.com/dotnet/roslyn ,Roslyn可以编译代码,解析语法树.CIIP中最需要的一个功能是模仿Visual Studio中的智能感知功能,Roslyn可是帮了大忙.

比如给出一段代码,并给出当前光标位置,Roslyn的相关API,就会结合整个project/solution计算出可以给出哪些提示条目,如:var x = new 光标在这里时,将会列出可以new出哪些类的名称,比如,引用了.net的程序集,自己项目中已经编写的类型等,当然,会过滤掉abstract的类型.

效果如下:

如果想了解CIIP中的建模模块的具体操作方法,请看这里.

那么,如何在自己的项目中集成上面的Roslyn呢?

第一步,来这里下载Roslyn,当然用netget在vs中获取也是可以的,不过有时很慢. https://github.com/tylike/CIIP/tree/master/packages 下接下载比较省心.

第二步,在nuget中搜索Avalonedit.是的,上图中的编辑器是Avalonedit,也是开源的,mono在linux下的sharpDevelop就是用的这个控件.需要注意的是,AvalonEdit是WPF控件,在Winform中可以用ElementHost这件控件连接WPF和普通winform的世界.

下面来看看代码,在CIIP中,下面这个路径是代码编辑器相关的内容:

https://github.com/tylike/CIIP/tree/master/CIIP.Module.Win/Editors/CodeEditor

首先,来看看这个SmartVisualStudio.cs,名字起的有点大哈, ^_^

代码不算多,才300多行,这个控件主要是先包装一下,做个自定义控件出来,包含了使用ElementHost.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CIIP.Module.BusinessObjects.SYS;
using System.Windows.Input;
using System.Diagnostics;
using ICSharpCode.AvalonEdit.CodeCompletion;
using System.Windows.Forms.Integration;
using ICSharpCode.AvalonEdit.Folding;
using Microsoft.CodeAnalysis;
using CIIP.Module.BusinessObjects.SYS.Logic;
using DevExpress.ExpressApp;
using System.IO;
using System.Xml;
using ICSharpCode.AvalonEdit.Highlighting;
using System.Text.RegularExpressions;
using DevExpress.XtraEditors; namespace CIIP.Module.Win.Editors
{
public partial class SmartVisualStudio : UserControl
{
protected SmartVisualStudio()
{
InitializeComponent();
} readonly SmartIDEWorkspace _workspace; public ICSharpCode.AvalonEdit.TextEditor Editor { get; set; } //IList<BusinessObject> businessObjects;
//MethodDefine method;
//private BusinessObjectPartialLogic logic;
private CsharpCode _codeObject;
readonly IDocumentProvider _document; public SmartVisualStudio(IObjectSpace os, CsharpCode value) : this()
{
this._codeObject = value; CreateEditor();
if (value != null)
{
if (value.Workspace != null)
{
this._workspace = (SmartIDEWorkspace) value.Workspace;
}
else
{
this._workspace = SmartIDEWorkspace.GetIDE(os);
}
this._document = value.Provider; } #region 预设置智能感知项目,如果是一个方法,就需要先看一下方法中可以用的智能感知条目列表 if (_document is IPartCodeProvider && _document!=null)
{
var code = value?.Code + "";
IList<ICompletionData> list = new List<ICompletionData>();
_workspace.GetIntellisenseItems(_document, , true, code, null, list);
} if (value == null)
{
Editor.IsEnabled = false;
} #endregion #region 设置环境 if (value != null)
{
tabSolution.Visibility = value.ShowSolutionFiles
? DevExpress.XtraBars.Docking.DockVisibility.Visible
: DevExpress.XtraBars.Docking.DockVisibility.Hidden;
if (value.ShowSolutionFiles)
{
solutionTreeView.Nodes.Clear();
solutionTreeView.MouseClick += SolutionTreeView_MouseClick;
var solution = solutionTreeView.Nodes.Add("Solution"); foreach (var item in _workspace.Workspace.CurrentSolution.Projects)
{
var projectNode = solution.Nodes.Add(item.Name, item.Name);
projectNode.Tag = item; var references = projectNode.Nodes.Add("引用", "引用");
foreach (var refence in item.MetadataReferences)
{
references.Nodes.Add(refence.Display);
} foreach (var doc in item.Documents.OrderBy(x=>x.Name))
{
var docNode = projectNode.Nodes.Add(doc.Name, doc.Name);
docNode.Tag = doc;
}
}
}
if (value.Diagnostics != null && value.Diagnostics.Count > )
{
this.SetDiagnosticMessage(value.Diagnostics);
}
} #endregion } private void SolutionTreeView_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
{
var path = fbd.SelectedPath;
foreach (var item in _workspace.Workspace.CurrentSolution.Projects.First().Documents)
{
//var file = File.(path + "\\" + item.Name);
File.WriteAllText(path + "\\" + item.Name, item.GetTextAsync().Result.ToString());
}
XtraMessageBox.Show("导出代码完成!");
}
}
} private void CreateEditor()
{
Editor = new ICSharpCode.AvalonEdit.TextEditor(); Editor.TextArea.TextEntering += TextArea_TextEntering;
Editor.TextArea.TextEntered += TextArea_TextEntered;
//Editor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
Editor.ShowLineNumbers = true; using (StreamReader s =
new StreamReader(AdmiralEnvironment.ApplicationPath + @"\\VSCSharp.xshd"))
{
using (XmlTextReader reader = new XmlTextReader(s))
{
Editor.SyntaxHighlighting =
ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader.Load(
reader,
HighlightingManager.Instance);
}
} Editor.FontFamily = new System.Windows.Media.FontFamily("Consolas");
Editor.FontSize = ;
//Editor.SyntaxHighlighting.MainRuleSet.Rules Editor.TextArea.IndentationStrategy =
new ICSharpCode.AvalonEdit.Indentation.CSharp.CSharpIndentationStrategy(Editor.Options);
var foldingManager = FoldingManager.Install(Editor.TextArea);
var foldingStrategy = new BraceFoldingStrategy(); this.elementHost1.Child = Editor;
} private void Listview_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && ErrorListView.SelectedItems.Count > )
{
var selected = ErrorListView.SelectedItems[];
var item = selected.Tag as Diagnostic;
GoogleTranslator.TranslateGoogleString(selected.Text);
//client.Translate("", selected.Text, "en", "zh-CHS", "text/plan", "general", "");
}
} private void Listview_DoubleClick(object sender, EventArgs e)
{
if (ErrorListView.SelectedItems.Count > )
{
var selected = ErrorListView.SelectedItems[];
var item = selected.Tag as Diagnostic;
if (_document is IPartCodeProvider)
{
var part = _document as IPartCodeProvider;
var code = _workspace.GetText(_document);
var begin = code.IndexOf(part.DefaultLocation);
var l = item.Location.SourceSpan;
if (l.Start > begin)
{
Editor.Select(l.Start - begin - part.DefaultLocation.Length - , l.Length > ? l.Length : );
}
}
else
{
var line = item.Location.GetLineSpan();
var path =line.Path;
var doc = _workspace.Workspace.CurrentSolution.Projects.First().Documents.First(x => x.Name == path);
OpenFile(doc);
Editor.Select(item.Location.SourceSpan.Start, item.Location.SourceSpan.Length);
Editor.ScrollToLine(line.StartLinePosition.Line);
}
}
} public bool Validated()
{
var diags = _workspace.GetDiagnostics(Editor.Text, this._document);
SetDiagnosticMessage(diags);
return ErrorListView.Items.Count == ;
} private void SetDiagnosticMessage(IEnumerable<Diagnostic> diags)
{
ErrorListView.Items.Clear();
if (diags != null)
{
var zhcn = System.Globalization.CultureInfo.CreateSpecificCulture("zh-CN");
foreach (var item in diags.Where(x => x.DefaultSeverity != DiagnosticSeverity.Hidden))
{
var line = item.Location.GetLineSpan().ToString(); var lvi = new ListViewItem(new string[] { item.Severity.ToString(), item.GetMessage(zhcn), line }, );
lvi.Tag = item;
ErrorListView.Items.Add(lvi);
}
} } private string SetStatusBarText()
{
return "行:" + Editor.TextArea.Caret.Position.Line + " 列:" + Editor.TextArea.Caret.Position.Column;
} //默认为没有输入
private int startTokenPosition = -;
private int inputedLen = ; private void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
{
Debug.WriteLine("TextArea_TextEntered:" + e.Text); if (completionWindow == null &&
(e.Text == "." || e.Text == " " || e.Text == "\t" || e.Text == "(" || e.Text == "["))
{
// Open code completion after the user has pressed dot:
completionWindow = new CompletionWindow(Editor.TextArea);
completionWindow.Width = ;
var data = completionWindow.CompletionList.CompletionData;
_workspace.GetIntellisenseItems(this._document, Editor.CaretOffset, e.Text != ".", Editor.Text, null, data);
completionWindow.Show();
completionWindow.Closed += delegate
{
completionWindow = null;
};
} if (e.Text == "\n")
{
this.Validated();
this.OnValueChanged?.Invoke(this, null);
}
} private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
{
Debug.WriteLine("TextArea_TextEntering:" + e.Text);
if (e.Text.Length > && completionWindow != null)
{
if (!char.IsLetterOrDigit(e.Text[]))
{
completionWindow.CompletionList.RequestInsertion(e);
}
}
} public event EventHandler OnValueChanged;
CompletionWindow completionWindow; public CsharpCode Code
{
get
{
if (this._codeObject != null)
this._codeObject.Code = Editor.Text;
return _codeObject;
}
set
{
_codeObject = value;
if (value == null)
{
Editor.Text = "";
}
else
{
Editor.Text = value.Code;
}
}
} private void solutionTreeView_DoubleClick(object sender, EventArgs e)
{
if (solutionTreeView.SelectedNode != null)
{
var s = solutionTreeView.SelectedNode.Tag as Document;
if (s != null)
{
OpenFile(s);
}
}
} private void OpenFile(Document s)
{
Editor.Text = _workspace.Workspace.CurrentSolution.Projects.Single(x => x.Id == s.Project.Id).Documents.Single(x => x.Name == s.Name).GetTextAsync().Result.ToString();
}
}
}

多数逻辑都是调用WorkSpace来工作的.

再来看看WorkSpace的代码:

他对应着VS中的solution所在容器.简单的来讲,下面的代码就是组装出一个Solution,Project,及每个文件,文件是根据CIIP的业务模型来生成的.业务模型与.net中的类型信息很相似,内容也稍多了些,此处先不详细说明了,有兴趣的同学可以读下源码.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using CIIP.Module.BusinessObjects.SYS;
using CIIP.Module.BusinessObjects.SYS.BOBuilder;
using CIIP.Module.BusinessObjects.SYS.Logic;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using CIIP;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Recommendations;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Formatting;
using System.Windows.Media.Imaging;
using ICSharpCode.AvalonEdit.CodeCompletion;
using System.Windows.Media;
using CIIP.Module.BusinessObjects.Flow;
using DevExpress.Xpo; namespace CIIP.Module.Win.Editors
{
/// <summary>
/// 用于编辑器的后台服务,包含了Solution等信息
/// </summary>
public class SmartIDEWorkspace
{
public static SmartIDEWorkspace GetIDE(IObjectSpace os)
{
return new SmartIDEWorkspace(os);
//if (Instance == null)
//{
// Instance = new SmartIDEWorkspace(os);
//}
//return Instance;
} public static SmartIDEWorkspace Instance { get; private set; } public AdhocWorkspace Workspace { get; } Project ModuleProject {
get { return Workspace.CurrentSolution.Projects.First(); }
} private IObjectSpace objectSpace; public SmartIDEWorkspace(IObjectSpace objectSpace)
{
this.Workspace = new AdhocWorkspace();// MSBuildWorkspace.Create();
this.objectSpace = objectSpace;
CreateSolution(); InitializeKeywordItems();
} string keywords = "var dynamic abstract as base break case catch checked continue default delegate do else event explicit extern false finally fixed for foreach goto if implicit in interface internal is lock namespace new null object operator out override params private protected public readonly ref return sealed sizeof stackalloc switch this throw true try typeof unchecked unsafe using virtual while bool byte char class const decimal double enum float int long sbyte short static string struct uint ulong ushort void"; private readonly List<CompletionData> keywordItmes = new List<CompletionData>(); //public string Code { get; } List<ImageSource> images = new List<ImageSource>(); private void InitializeKeywordItems()
{
var path = AdmiralEnvironment.ApplicationPath + "\\AutoCompleteIcons\\"; for (int i = ; i <= ; i++)
{
images.Add(new BitmapImage(new Uri(path + i + ".bmp")));
} var ks = keywords.Split(' '); foreach (var s in ks)
{
keywordItmes.Add(new CompletionData(s, images[], "", TokenType.iKeyWords));
}
} public EmitResult Compile()
{
var outputPath = AdmiralEnvironment.UserDefineBusinessTempFile.FullName;
foreach (var doc in this.ModuleProject.Documents)
{
Debug.WriteLine(doc.Name);
}
var pdb = outputPath + ".pdb";
return ModuleProject.GetCompilationAsync().Result.Emit(outputPath);
} public IEnumerable<Diagnostic> GetDocumentDiagnostic(Guid documentGuid)
{
return Documents[documentGuid].GetSemanticModelAsync().Result.GetDiagnostics();
} protected void CreateSolution()
{
CreateModuleProject();
}
List<MetadataReference> CollectReferencedAssemblies()
{
List<MetadataReference> refs = new List<MetadataReference>();
var asms = AppDomain.CurrentDomain.GetAssemblies();
foreach (var item in typeof(ERPModule).Assembly.GetReferencedAssemblies())
{
var asm = asms.SingleOrDefault(x => x.FullName == item.FullName);
if (asm == null)
{
asm = Assembly.Load(item);
}
if (asm == null)
{
throw new Exception("Not found referenced assembly:" + item.FullName);
}
refs.Add(MetadataReference.CreateFromFile(asm.Location));
}
refs.Add(MetadataReference.CreateFromFile(typeof(CIIP.Module.ERPModule).Assembly.Location));
refs.Add(MetadataReference.CreateFromFile(typeof(XPCollection).Assembly.Location));
return refs;
} private void CreateModuleProject()
{
var refs = CollectReferencedAssemblies(); var moduleProjectName = "RuntimeModule"; var moduleProjectID = ProjectId.CreateNewId(); var versionStamp = VersionStamp.Create(); var projInfo = ProjectInfo.Create(moduleProjectID, versionStamp, moduleProjectName, moduleProjectName,
LanguageNames.CSharp,
compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); projInfo = projInfo.WithMetadataReferences(refs); Workspace.AddProject(projInfo); //取得所有用户定义的业务类型,并生成文档.
var businessObjects = this.objectSpace.GetObjects<BusinessObject>(new BinaryOperator("IsRuntimeDefine", true)); CreateAssembyInfoDocument();
CreateRuntimeModule();
Documents.Clear();
foreach (var bo in businessObjects)
{
CreateDocument(bo);
} var partialLogics = this.objectSpace.GetObjects<BusinessObjectPartialLogic>(null,true);
foreach (var logic in partialLogics)
{
CreateDocument(logic);
}
var flowactions = this.objectSpace.GetObjects<FlowAction>(null, true);
foreach (var flowacion in flowactions)
{
CreateDocument(flowacion);
}
var layouts = this.objectSpace.GetObjects<BusinessObjectLayout>();
foreach (var item in layouts)
{
CreateDocument(item);
}
var controllers = this.objectSpace.GetObjects<RuntimeController>(null,true);
foreach (var item in controllers)
{
CreateDocument(item);
}
} string AggregatedAttribute = typeof(AggregatedAttribute).FullName; public static string GetCommonUsing()
{
return BusinessObject.CommonUsing();
} private Dictionary<Guid, Document> Documents = new Dictionary<Guid, Document>();
private Dictionary<Guid, SemanticModel> SemanticModels = new Dictionary<Guid, SemanticModel>(); public void CreateAssembyInfoDocument()
{ #region GetVersion var ver = BusinessBuilder.GetVersion(AdmiralEnvironment.UserDefineBusinessFile); if (ver != null)
{
ver = new Version(ver.Major + , ver.Minor, ver.Build, ver.Revision);
}
else
{
ver = new Version(, , , );
} #endregion var str = $"[assembly: {typeof (AssemblyVersionAttribute).FullName}(\"{ver.ToString()}\")]\n";
Workspace.AddDocument(ModuleProject.Id, "AssemblyInfo.cs", SourceText.From(str,Encoding.UTF8));
} public void CreateRuntimeModule()
{
var str =
$"public class RuntimeModule:{typeof(RuntimeModuleBase).FullName} {{ public RuntimeModule():base(){{}} }}\n";
Workspace.AddDocument(ModuleProject.Id, "RunttimeModule.cs", SourceText.From(str,Encoding.UTF8)); } #region document provider services #region create document
private void CreateDocument(IDocumentProvider documentProvider)
{ var doc = Workspace.AddDocument(ModuleProject.Id, documentProvider.GetFileName() + ".cs", SourceText.From(documentProvider.GetCode(),Encoding.UTF8)); var updated = Workspace.TryApplyChanges(doc.Project.Solution);
Debug.WriteLine("Updated:" + updated);
Documents.Add(documentProvider.GetDocumentGuid(), doc); SemanticModels.Add(documentProvider.GetDocumentGuid(), doc.GetSemanticModelAsync().Result);
}
#endregion #region get text
public string GetText(IDocumentProvider doc)
{
return Documents[doc.GetDocumentGuid()].GetTextAsync().Result.ToString();
}
#endregion #region update text
private void UpdateText(string text, IDocumentProvider doc)
{
SourceText sourceText = SourceText.From(text,Encoding.UTF8);
var document = Documents[doc.GetDocumentGuid()];
document = document.WithText(sourceText);
var rs = Workspace.TryApplyChanges(document.Project.Solution); Debug.WriteLine("enter updated:" + rs);
//重要:当更改了项目后,文档实例被变化了,必须重新保存
document = this.ModuleProject.Documents.First(x => x.Id == document.Id);
Documents[doc.GetDocumentGuid()] = document;
SemanticModels[doc.GetDocumentGuid()] = document.GetSemanticModelAsync().Result;
}
#endregion #region get intellisense items
/// <summary>
/// 取得光标位置的可用智能感知项目
/// </summary>
/// <param name="bodytext">代码</param>
/// <param name="logic">对应项目</param>
/// <param name="index">光标所在位置</param>
/// <returns>可能智能感知项目</returns>
public IEnumerable<ISymbol> GetRecommendedSymbolsAtPositionAsync(string bodytext, IDocumentProvider logic, int index)
{
if (logic is IPartCodeProvider)
{
var doc = Documents[logic.GetDocumentGuid()];
bodytext = (logic as IPartCodeProvider).ReplaceNewCode(doc.GetTextAsync().Result.ToString(), bodytext); //var doc = Documents[method.BusinessObject.Oid];
//var newText = method.ReplaceNewCode(doc.GetTextAsync().Result.ToString(), bodytext); //UpdateText(newText, method.BusinessObject); //var semanticModel = SemanticModels[method.BusinessObject.Oid];
//return Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, pos, Workspace).Result;
} UpdateText(bodytext, logic);
if (logic is IPartCodeProvider)
{
var define = (logic as IPartCodeProvider).DefaultLocation;
index = bodytext.IndexOf(define) + define.Length + index + ;
} var semanticModel = SemanticModels[logic.GetDocumentGuid()];
return Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, index, Workspace).Result;
} public void GetIntellisenseItems(IDocumentProvider document, int cartIndex,
bool needKeyword, string code, string inputed, IList<ICompletionData> result)
{
IEnumerable<ISymbol> symbols = GetRecommendedSymbolsAtPositionAsync(code, document, cartIndex);
ProcessSymbols(needKeyword, symbols, inputed, result);
} private void ProcessSymbols(bool needKeyword, IEnumerable<ISymbol> symbols, string inputed, IList<ICompletionData> list)
{ TokenType idx = TokenType.iValueType; if (!string.IsNullOrEmpty(inputed))
{
symbols = symbols.Where(x => x.Name.Contains(inputed)).ToArray();
} if (symbols == null)
{ } foreach (var symbol in symbols)
{
if (symbol is INamespaceSymbol)
{
idx = TokenType.iNamespace;
}
else if (symbol is ITypeSymbol)
{
idx = TokenType.iClass;
}
else if (symbol is IMethodSymbol)
{
var m = symbol as IMethodSymbol;
if (m.IsExtensionMethod)
{
idx = TokenType.iMethodShortCut;
}
else if (symbol.DeclaredAccessibility == Accessibility.Public)
{
idx = TokenType.iMethod;
}
else if (symbol.DeclaredAccessibility == Accessibility.Protected)
{
idx = TokenType.iMethodProtected;
}
else if (symbol.DeclaredAccessibility == Accessibility.Private)
{
idx = TokenType.iMethodPrivate;
}
else if (symbol.DeclaredAccessibility == Accessibility.Internal)
{
idx = TokenType.iMethodFriend;
}
else
{
idx = TokenType.iMethodShortCut;
}
}
else if (symbol is IPropertySymbol)
{
if (symbol.DeclaredAccessibility == Accessibility.Public)
{
idx = TokenType.iProperties;
}
else if (symbol.DeclaredAccessibility == Accessibility.Protected)
{
idx = TokenType.iPropertiesProtected;
}
else if (symbol.DeclaredAccessibility == Accessibility.Private)
{
idx = TokenType.iPropertiesPrivate;
}
else if (symbol.DeclaredAccessibility == Accessibility.Internal)
{
idx = TokenType.iPropertiesFriend;
}
else
{
idx = TokenType.iPropertiesShortCut;
}
}
else if (symbol is IFieldSymbol)
{
if (symbol.DeclaredAccessibility == Accessibility.Public)
{
idx = TokenType.iField;
}
else if (symbol.DeclaredAccessibility == Accessibility.Protected)
{
idx = TokenType.iFieldProtected;
}
else if (symbol.DeclaredAccessibility == Accessibility.Private)
{
idx = TokenType.iFieldPrivate;
}
else if (symbol.DeclaredAccessibility == Accessibility.Internal)
{
idx = TokenType.iFieldFriend;
}
else
{
idx = TokenType.iFieldShortCut;
}
}
else if (symbol is IEventSymbol)
{
if (symbol.DeclaredAccessibility == Accessibility.Public)
{
idx = TokenType.iEvent;
}
else if (symbol.DeclaredAccessibility == Accessibility.Protected)
{
idx = TokenType.iEventProtected;
}
else if (symbol.DeclaredAccessibility == Accessibility.Private)
{
idx = TokenType.iEventPrivate;
}
else if (symbol.DeclaredAccessibility == Accessibility.Internal)
{
idx = TokenType.iEventFriend;
}
else
{
idx = TokenType.iEventFriend;
}
}
else if (symbol is ILocalSymbol)
{
idx = TokenType.iValueType;
}
else if (symbol is IParameterSymbol)
{
idx = TokenType.iField;
}
else if (symbol is IPreprocessingSymbol)
{
idx = TokenType.iProperties;
}
//if (idx != (int) AutoListIcons.iNamespace)
if (symbol is IMethodSymbol)
{
var m = symbol as IMethodSymbol;
list.Add(
new CompletionData(
symbol.Name + "(" + string.Join(",", m.Parameters.Select(x => x.Type.Name)) + ")",
images[(int)idx], m.ToString(), idx));
}
else
{
list.Add(new CompletionData(symbol.Name, images[(int)idx], "", idx));
}
} if (needKeyword)
{
foreach (var item in keywordItmes)
{
list.Add(item);
}
}
}
#endregion #region get diagnostics
public IEnumerable<Diagnostic> GetDiagnostics(string text, IDocumentProvider method)
{
if (method is IPartCodeProvider)
{
var doc = Documents[method.GetDocumentGuid()];
text = (method as IPartCodeProvider).ReplaceNewCode(doc.GetTextAsync().Result.ToString(), text);
}
UpdateText(text, method);
var rst = SemanticModels[method.GetDocumentGuid()].GetDiagnostics();
return rst;
}
#endregion #endregion
public string GetAllCode()
{
var sb = new StringBuilder(); foreach (var document in ModuleProject.Documents)
{
var root = document.GetSyntaxRootAsync().Result;
var formattedResult = Formatter.Format(root, this.Workspace);
var code = formattedResult.GetText().ToString(); sb.AppendLine(code);
}
return sb.ToString();
} }
}

值得说明的是,取得当前光标所在位置的可用智能感知项目是通过这句关键代码实现的.

            return Recommender.GetRecommendedSymbolsAtPositionAsync(semanticModel, index, Workspace).Result;

另外,可以从图中看出,图中显示的代码只是片断,并没有类的定义,using,命名空间的内容,这里只是使用了一个小技巧,即:将当前编辑器中的代码嵌入到了写好的类型文件中,在敲下代码时,不停的去替换代码,最终得到正确的编码文件,然后再去取得智能感知的内容.

除了建模中用到了代码编辑器,在单据转换流程中,也有相关应用,下篇我将描述实现思路,先上一个图看看效果吧!:D

没有技术说明文档的开源都是耍流氓:微软Roslyn编译即服务在CIIP中具体应用(上)的更多相关文章

  1. 原创SQlServer数据库生成简单的说明文档小工具(附源码)

    这是一款简单的数据库文档生成工具,主要实现了SQlServer生成说明文档的小工具,目前不够完善,主要可以把数据库的表以及表的详细字段信息,导出到 Word中,可以方便开发人员了解数据库的信息或写技术 ...

  2. 原创SQlServer数据库生成简单的说明文档包含(存储过程、视图、数据库批量备份)小工具(附源码)

    这是一款简单的数据库文档生成工具,主要实现了SQlServer生成说明文档的小工具,目前不够完善,主要可以把数据库的表以及表的详细字段信息,导出到 Word中,可以方便开发人员了解数据库的信息或写技术 ...

  3. 为ASP.NET WEB API生成人性化说明文档

    一.为什么要生成说明文档 我们大家都知道,自己写的API要供他人调用,就需要用文字的方式将调用方法和注意事项等写成一个文档以更好的展示我们设计时的想法和思路,便于调用者更加高效的使用我们的API. 当 ...

  4. showdoc 开源在线api&&技术文档管理工具

    showdoc 是一个很不错的api 以及技术文档管理工具 环境准备 doker-copose 文件 version: "3" services: doc: image: regi ...

  5. BasicExcel说明文档

    BasicExcel说明文档 BasicExcel原始链接:http://www.codeproject.com/Articles/13852/BasicExcel-A-Class-to-Read-a ...

  6. 如何使用Swagger为.NET Core 3.0应用添加JWT授权说明文档

    简介 本教程采用WHY-WHAT-HOW黄金圈思维模式编写,黄金圈法则强调的是从WHY为什么学,到WHAT学到什么,再到HOW如何学.从模糊到清晰的学习模式.大家的时间都很宝贵,我们做事前先想清楚为什 ...

  7. 浏览器内核控制Meta标签说明文档

    浏览器内核控制Meta标签说明文档 原文链接 背景介绍 由于众所周知的情况,国内的主流浏览器都是双核浏览器:基于Webkit内核用于常用网站的高速浏览.基于IE的内核用于兼容网银.旧版网站.以360的 ...

  8. RabbitMq 技术文档

    RabbitMq 技术文档 目录 1 AMQP简介 2 AMQP的实现 3 RabbitMQ简介 3.1 概念说明 3.2 消息队列的使用过程 3.3 RabbitMQ的特性 4 RabbitMQ使用 ...

  9. SWFUpload 2.5.0版 官方说明文档 中文翻译版

    原文地址:http://www.cnblogs.com/youring2/archive/2012/07/13/2590010.html#setFileUploadLimit SWFUpload v2 ...

随机推荐

  1. fio

    h3.western { font-family: "Liberation Sans", sans-serif; font-size: 14pt } h3.cjk { font-f ...

  2. Memcached 笔记与总结(8)Memcached 的普通哈希分布算法和一致性哈希分布算法命中率对比

    准备工作: ① 配置文件 config.php ② 封装 Memcached 类 hash.class.php,包含普通哈希算法(取模)和一致性哈希算法 ③ 初始化 Memcached 节点信息 in ...

  3. 分割excel sheet

    Sub split_sheet() '输入用户想要拆分的工作表 Dim sheet_name sheet_name = Application.InputBox("请输入拆分工作表的名称:& ...

  4. CSS 伪元素&伪类

    单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素 伪元素 属性 描述 CSS :first-letter 向文本的第一个字母添加特殊样式 1 :first-line 向文本的首行添加特殊 ...

  5. 《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK THREE ...

  6. IBM服务器诊断面板

    IBM服务器一般会有一个服务器操作员信息面板(诊断面板),服务器一般的硬件故障都会在诊断面板上提示,但这些提示可能只是一个大概的诊断故障,有助于系统管理员更好的维护. 一.IBM X3650 M3诊断 ...

  7. 委托(delegate)的三种调用方式:同步调用,异步调用,异步回调(转载)

    下面为即将被调用的方法: public delegate int AddHandler(int a,int b); public class 加法类 { public static int Add(i ...

  8. Linux:实现Hadoop集群Master无密码登录(SSH)各个子节点

    以下所介绍的安装方式都是在线安装方式,如果你需要连网请参考:Linux:宿主机通过桥接方式连接的VMware内部Linux14.04虚拟机(静态IP)实现上网方案 环境: OS:Linux Ubunt ...

  9. Node.js的核心与红利(zz)

    唯有明晰历史,才能了然当下,预知未来.作者从历史角度解读Node.js,帮助读者透过猜忌和谣言,看清真实的Node.js,了解Node.js的核心与红利. 令人惴惴不安的Node.js 我们越来越频繁 ...

  10. 在CentOS 7上安装Node.js的4种方法

    一.源码安装 1.下载源码(官网查看最新版本链接) wget http://nodejs.org/dist/v0.10.30/node-v0.10.30.tar.gz 2.解压源码 tar xzvf ...