我有一些簡化示例代碼,希望我試圖完成。如何使用Roslyn獲取編譯時間常量值
OptionAtrribute.cs
using System;
public class OptionAttribute : Attribute
{
public OptionAttribute(string option)
{
this.PickedOption = option;
}
public string PickedOption { get; private set; }
}
Options.cs
using System;
public class Options
{
public const string Cat = "CT";
public const string Dog = "DG";
public const string Monkey = "MNKY";
}
SomeClass.cs
using System;
[Option(Options.Dog)]
public class SomeClass
{
}
哪有我在「SomeClass」類上獲得「OptionAttribute」並獲得「PickedOption」值?
更新
我不問如何使用反射。這是用於在保存代碼的文件保存時生成代碼。我沒有一個更新的DLL在這一點上,所以反射將無法正常工作我正在嘗試使用Roslyn來解析實際的文件。 下面是我不得不嘗試
string solutionPath = @"C:\Project\Project.sln";
var msWorkspace = MSBuildWorkspace.Create();
var solution = await msWorkspace.OpenSolutionAsync(solutionPath);
var project = solution.Projects.FirstOrDefault(p => p.Name == "Project1");
var compilation = await project.GetCompilationAsync();
var document = project.Documents.FirstOrDefault(d => d.Name == "Code.cs");
SyntaxTree syntaxTree = null;
document.TryGetSyntaxTree(out syntaxTree);
var semanticModel = compilation.GetSemanticModel(syntaxTree);
var commandCategoryAttribute = compilation.GetTypeByMetadataName("Project1.OptionAttribute");
var classDeclaration = syntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Skip(2).FirstOrDefault();
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration);
var attrSymbol = classSymbol.GetAttributes().FirstOrDefault(a => a.AttributeClass.MetadataName == commandCategoryAttribute.MetadataName);
var attrSyntax = classDeclaration.AttributeLists.FirstOrDefault().Attributes.FirstOrDefault();
我的解決方案
我得到它的工作!
public void Test()
{
string solutionPath = @"C:\Project\Project.sln";
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
var project = solution.Projects.FirstOrDefault(p => p.Name == "Project1");
var compilation = project.GetCompilationAsync().Result;
var document = project.Documents.FirstOrDefault(d => d.Name == "SomeClass.cs");
SyntaxTree syntaxTree = null;
document.TryGetSyntaxTree(out syntaxTree);
SemanticModel semanticModel = compilation.GetSemanticModel(syntaxTree);
ClassDeclarationSyntax classDeclaration = syntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().FirstOrDefault();
var attr = classDeclaration.AttributeLists.SelectMany(a => a.Attributes).FirstOrDefault(a => a.Name.ToString() == "Option");
var exp = attr.ArgumentList.Arguments.First().Expression;
string value = null;
var mem = exp as MemberAccessExpressionSyntax;
if (mem != null)
{
value = ResolveMemberAccess(mem, solution, compilation)?.ToString();
}
else
{
var lit = exp as LiteralExpressionSyntax;
if (lit != null)
{
value = semanticModel.GetConstantValue(lit).Value?.ToString();
}
}
}
public object ResolveMemberAccess(MemberAccessExpressionSyntax memberSyntax, Solution solution, Compilation compilation)
{
var model = compilation.GetSemanticModel(memberSyntax.SyntaxTree);
var memberSymbol = model.GetSymbolInfo(memberSyntax).Symbol;
var refs = SymbolFinder.FindReferencesAsync(memberSymbol, solution).Result.FirstOrDefault();
if (refs != null)
{
var defSyntax = refs.Definition.DeclaringSyntaxReferences.First();
var parent = compilation.GetSemanticModel(defSyntax.SyntaxTree);
var syn = defSyntax.GetSyntax();
var literal = syn.DescendantNodes().OfType<LiteralExpressionSyntax>().FirstOrDefault();
if (literal != null)
{
var val = parent.GetConstantValue(literal);
return val.Value;
}
else
{
var memberAccess = syn.DescendantNodes().OfType<MemberAccessExpressionSyntax>().FirstOrDefault();
if (memberAccess != null)
{
return ResolveMemberAccess(memberAccess, solution, compilation);
}
}
}
return null;
}
謝謝!
的可能的複製[?我如何讀取在運行時類的屬性(http://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime) –