2012-03-01 16 views
29

से मैं निम्नलिखित की तरह कुछ कोडित हैतक पहुँचना विशेषता की जानकारी DTE

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

मैं EnvDTE उपयोग करने के लिए CodeElementtypeof द्वारा संदर्भित के लिए एक संदर्भ प्राप्त करना चाहते हैं। मैं कैसे विशेषता तर्क के लिए एक संदर्भ पाने के लिए पता है, और मैं Value उपयोग कर सकते हैं, लेकिन है कि मुझे स्ट्रिंग typeof(MyCustomType) देता है।

अगर मैं Value उपयोग करते हैं, मैं स्ट्रिंग को तोड़ने और फिर प्रकार है, जो बालों हो जाता है अगर वहाँ एक ही नाम पर अलग नामस्थान के साथ दो प्रकार के होते हैं खोजने की कोशिश करने के लिए है।

क्या ऐसा करने का कोई आसान तरीका है?

+4

तो कैसे आप विशेषता तर्क के लिए एक संदर्भ मिलता है? – Maslow

+3

क्या आपने रोज़लिन में देखा है? यह उन सुविधाओं को पेश करना चाहिए जिन्हें आप ढूंढ रहे हैं। – jessehouwing

+0

क्या आपने विशेषता की पूर्ण नाम संपत्ति की जांच की है? –

उत्तर

-2

आप एक तरह से उपयोग करने के लिए कोशिश कर सकते हैं Get all methods that are decorated with a specific attribute using T4/EnvDTE

+2

यह एक अच्छा सौदा अधिक विशिष्टता का उपयोग कर सकता है; कम से कम, प्रासंगिक भागों को संक्षेप में सारांशित करें। बस इसे देखकर मैं यह नहीं बता सका कि आप क्या कह रहे थे। –

3

वहाँ यह करने के लिए एक आसान तरीका है वर्णित?

नहीं, मैं ऐसा नहीं सोचता, कम से कम एक < = VS2013 के लिए, ऐसा लगता है कि CodeAttributeArgument किसी भी आगे जाने नहीं करता है, जो शर्म की बात है है। वे CodeAttributeArgument2 है कि ValueCodeExpr के रूप में जारी किया है चाहिए: \ ..

आप का उपयोग करते हैं> = VS2014, आप रोसलिन तक पहुँच प्राप्त कर सकते हैं, और यह आसान हो जाना चाहिए - वास्तव में नहीं जानता कि कैसे आप वीएस एक्सटेंशन के अंदर रोस्लिन का उपयोग कर सकते हैं, इंतजार करना और देखना है।

आदेश गुण पाने के लिए, आप सहायक वी.एस. उपयोग कर सकते हैं:

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 के लिए, रोसलिन एकीकरण का एक उदाहरण यहां से पाया जा सकता है: https://github.com/tomasr/roslyn-colorizer/blob/master/RoslynColorizer/RoslynColorizer.cs

यह निश्चित रूप से एक बहुत आसान की तुलना में यह वर्तमान CodeModel साथ है हो जाएगा।

संबंधित मुद्दे