gpt4 book ai didi

c# - 从 DTE 访问属性信息

转载 作者:IT王子 更新时间:2023-10-29 04:13:15 26 4
gpt4 key购买 nike

我编写了如下代码:

[Attrib(typeof(MyCustomType))]
public class TargetType
{
// .....
}

我想使用 EnvDTE 获取对 typeof 引用的 CodeElement 的引用。我知道如何获取对属性参数的引用,并且我可以使用 Value,但这给了我字符串 typeof(MyCustomType)

如果我使用 Value,我必须分解字符串然后尝试找到类型,如果有两个名称相同但命名空间不同的类型,这会变得很麻烦。

有更简单的方法吗?

最佳答案

Is there an easier way to do this?

不,我不这么认为,至少对于 <= VS2013,CodeAttributeArgument 似乎没有更进一步,这很遗憾。他们应该发布 CodeAttributeArgument2,它的 ValueCodeExpr :\..

如果您使用 >=VS2014,您可以访问 Roslyn,并且它应该 变得更容易 - 不知道如何在 VS 扩展中访问 roslyn ,还得拭目以待。

为了获取属性,您可以使用 VS 助手:

public List<CodeElement> GetAllCodeElementsOfType(
CodeElements elements,
vsCMElement elementType,

bool includeExternalTypes)
{
var ret = new List<CodeElement>();

foreach (CodeElement elem in elements)
{
// iterate all namespaces (even if they are external)
// > they might contain project code
if (elem.Kind == vsCMElement.vsCMElementNamespace)
{
ret.AddRange(
GetAllCodeElementsOfType(
((CodeNamespace)elem).Members,
elementType,
includeExternalTypes));
}

// if its not a namespace but external
// > ignore it
else if (elem.InfoLocation == vsCMInfoLocation.vsCMInfoLocationExternal && !includeExternalTypes)
continue;

// if its from the project
// > check its members
else if (elem.IsCodeType)
{
ret.AddRange(
GetAllCodeElementsOfType(
((CodeType)elem).Members,
elementType,
includeExternalTypes));
}

if (elem.Kind == elementType)
ret.Add(elem);
}
return ret;
}

原始来源:https://github.com/PombeirP/T4Factories/blob/master/T4Factories.Testbed/CodeTemplates/VisualStudioAutomationHelper.ttinclude

与此同时,您可以使用回溯解决方案,这不是很好,但它应该可以工作,还没有完全 100% 地测试它。基本思想是从类开始向后跟踪,并跟踪类路径中的不同命名空间/使用。如果要解析类型,这将尝试模拟真正的编译器几乎会做什么:

 var solution = (Solution2) _applicationObject.Solution;
var projects = solution.Projects;
var activeProject = projects
.OfType<Project>()
.First();

// locate my class.
var myClass = GetAllCodeElementsOfType(
activeProject.CodeModel.CodeElements,
vsCMElement.vsCMElementClass, false)
.OfType<CodeClass2>()
.First(x => x.Name == "Program");

// locate my attribute on class.
var mySpecialAttrib = myClass
.Attributes
.OfType<CodeAttribute2>()
.First();



var attributeArgument = mySpecialAttrib.Arguments
.OfType<CodeAttributeArgument>()
.First();

string myType = Regex.Replace(
attributeArgument.Value, // typeof(MyType)
"^typeof.*\\((.*)\\)$", "$1"); // MyType*/

var codeNamespace = myClass.Namespace;
var classNamespaces = new List<string>();

while (codeNamespace != null)
{
var codeNs = codeNamespace;
var namespaceName = codeNs.FullName;

var foundNamespaces = new List<string> {namespaceName};

// generate namespaces from usings.
var @usings = codeNs.Children
.OfType<CodeImport>()
.Select(x =>
new[]
{
x.Namespace,
namespaceName + "." + x.Namespace
})
.SelectMany(x => x)
.ToList();

foundNamespaces.AddRange(@usings);

// prepend all namespaces:
var extra = (
from ns2 in classNamespaces
from ns1 in @usings
select ns1 + "." + ns2)
.ToList();

classNamespaces.AddRange(foundNamespaces);
classNamespaces.AddRange(extra);

codeNamespace = codeNs.Parent as CodeNamespace;
if (codeNamespace == null)
{
var codeModel = codeNs.Parent as FileCodeModel2;
if (codeModel == null) return;

var elems = codeModel.CodeElements;
if (elems == null) continue;

var @extraUsings = elems
.OfType<CodeImport>()
.Select(x => x.Namespace);

classNamespaces.AddRange(@extraUsings);
}
}

// resolve to a type!
var typeLocator = new EnvDTETypeLocator();
var resolvedType = classNamespaces.Select(type =>
typeLocator.FindTypeExactMatch(activeProject, type + "." + myType))
.FirstOrDefault(type => type != null);

你需要EnvDTETypeLocator也是。

对于 VS2015,可以从此处找到 roslyn 集成的示例:https://github.com/tomasr/roslyn-colorizer/blob/master/RoslynColorizer/RoslynColorizer.cs

它肯定会比使用当前的 CodeModel 容易得多。

关于c# - 从 DTE 访问属性信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9520802/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com