前段时间我发布了 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. Memcached 笔记与总结(7)增加虚拟节点

    仅仅把 Memcached 服务器集群地址通过一致性哈希转映射在圆环上,可能会出现数据不能均匀地分配给各台 Memcached 服务器. 解决方案是引入虚拟节点,就是把每个映射在圆环上的服务器地址(物 ...

  2. EntityFramework SQLiteCodeFirst 自动创建数据库 关闭级联删除

    外键的级联删除: 如A表中有主键idA, B表中设置外键(ForeignKey)为A表中的主键idA, 当A表中的记录被删除时, B表中所有引用此条记录的记录(即所有外键为idA的记录)将自动被删除 ...

  3. 【五子棋AI循序渐进】——多线程搜索

    关于多线程搜索,有很多方法来实现,很多文章推荐基于MTD(F)的方式.好处不言而喻,不过我的程序中采用的是基于PVS的多线程搜索.实现起来主要是这几个方面问题需要解决: 1.置换表的互斥访问. 2.局 ...

  4. Java学习-047-数值格式化及小数位数四舍五入

    此小工具类主要用于数值四舍五入.数值格式化输出,很简单,若想深入研究,敬请自行查阅 BigDecimal 或 DecimalFormat 的 API,BigDecimal.setScale(位数,四舍 ...

  5. Bugzilla说明

    简介 Bugzilla是Mozilla公司向我们提供的一个开源的免费缺陷跟踪工具.作为一个产品缺陷的记录及跟踪工具,它能够为你建立一个完善的Bug跟踪体系,包括报告Bug.查询Bug记录并产生报表.处 ...

  6. 利用开源jPlayer播放.flv视频文件

    最近工作中用到视频播放,在网上搜索对比了好几款开源播放插件后,觉得 jPlayer 是比较不错的,故作此记录! 接下来先快速的展示一下 利用jPlayer播放.flv视频的效果: <!DOCTY ...

  7. java基础算法-快速排序

    玩博客园很多年,第一次写点什么,就从基础开始吧.最近去面试,发现自己算法忘光了,赶紧复习下.以下代码自带测试类,复制进eclipse中右键 run as -->java application ...

  8. overflow遭遇场景

    没有设置高度而由内容撑高的子div在遇到固定高度的父div,想做一个离上边缘有间距的效果,给padding-top会同时撑大父div,给margin-top会把父div拉下来,这时候的子div像是紧紧 ...

  9. 浏览器网页判断手机是否安装IOS/Android客户端程序

    IOS 原理如下: 为HTML页面中的超链接点击事件增加一个setTimeout方法. 如果在iPhone上面500ms内,本机有应用程序能解析这个协议并打开程序,则这个回调方法失效: 如果本机没有应 ...

  10. Leetcode: All O`one Data Structure

    Implement a data structure supporting the following operations: Inc(Key) - Inserts a new key with va ...