2013-01-03 35 views
10

क्या डिज़ाइन समय पर प्रतिबिंब पूर्व-संकलन करने का कोई तरीका है?डिजाइन समय प्रतिबिंब

मेरा इरादा कुछ इंटरफेस को लागू करने वाले वर्गों के आधार पर कस्टम कोड को थूकने के लिए टी 4 का उपयोग करना है। मुझे पता है कि मैं प्रतिबिंब पर कॉल कर सकता हूं, लेकिन मैं टी 4 स्क्रिप्ट को संकलित करने से पहले अतिरिक्त कोड थूकना चाहता हूं, अन्यथा मुझे कोड को दो बार संकलित करने की आवश्यकता होगी, एक बार डीएल उत्पन्न करने के लिए, दो बार पहले जेनरेट किए गए डीएल पर प्रतिबिंबित करने और टी जोड़ने के लिए अतिरिक्त मचान

क्या डिजाइन समय पर प्रतिबिंब करने का कोई तरीका है?

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

+0

पर कोड द्वारा प्रेरित किया गया था क्या एक ही प्रोजेक्ट में टेम्पलेट्स और कक्षाएं हैं? मैं बस अनुमान लगा रहा हूं, लेकिन अगर आप विभिन्न परियोजनाओं में थे तो शायद आप आदेश पर बेहतर नियंत्रण कर सकते हैं, इसलिए कोई दूसरे के बाद संकलित कर सकता है। – Kobi

+0

हाँ मैंने इसके बारे में भी सोचा, लेकिन आप अभी भी अपनी परियोजना को एक-एक करके बनाते हैं, जब तक कि निर्माण को रोकने का कोई तरीका न हो, टी 4 चलाएं, रोकें। – Alwyn

+1

यदि टेम्पलेट पीढ़ी इसका एक हिस्सा है तो आपको बिल्ड को रोकना नहीं है: [बिल्ड प्रक्रिया में कोड जनरेशन] (http://msdn.microsoft.com/en-us/library/ee847423.aspx)। मैंने वास्तव में ऐसा कभी नहीं किया है, और यह सुनिश्चित नहीं है कि टेम्पलेटिंग इंजन किस संदर्भ में चलता है, लेकिन ऐसा लगता है कि यह काम कर सकता है। – Kobi

उत्तर

21

वास्तव में Visual Studio Automation द्वारा प्रदान किए गए कोडमोडेल के आधार पर कोड प्री-बिल्ड उत्पन्न करने का एक तरीका है: प्रोजेक्ट इंटरफेस एक प्रॉपर्टी "कोडमोडेल" प्रदान करता है जिसमें उस परियोजना में सभी मॉडल कलाकृतियों का एक ग्राफ शामिल है। कक्षाओं, इंटरफेस, गुणों, ... के आधार पर आप अपना आउटपुट कोड जेनरेट करने के लिए इसे पार करना चाहते हैं।

dandrejw पहले से ही Tangible T4-Editor का उल्लेख किया है। यह एक मुफ्त टेम्पलेट गैलरी मिल गया है। एक पुन: प्रयोज्य टेम्पलेट "मूर्त दृश्य स्टूडियो ऑटोमेशन हेल्पर" है जो आपके मामले में बेहद सहायक होना चाहिए। इस टेम्पलेट का उपयोग करके आप इस तरह अपना मुद्दा हल कर सकते हैं:

यह टीटी टेम्पलेट के भीतर कोड है जो INOTifyPropertyChanged को लागू करने वाले सभी वर्गों का पता लगाता है।

<# 
    // get a reference to the project of this t4 template 
    var project = VisualStudioHelper.CurrentProject; 
    // get all class items from the code model 
    var allClasses = VisualStudioHelper.GetAllCodeElementsOfType(project.CodeModel.CodeElements, EnvDTE.vsCMElement.vsCMElementClass, false); 

    // iterate all classes 
    foreach(EnvDTE.CodeClass codeClass in allClasses) 
    { 
     // get all interfaces implemented by this class 
     var allInterfaces = VisualStudioHelper.GetAllCodeElementsOfType(codeClass.ImplementedInterfaces, EnvDTE.vsCMElement.vsCMElementInterface, true); 
     if (allInterfaces.OfType<EnvDTE.CodeInterface>() 
         .Any(i => i.Name == "INotifyPropertyChanged")) 
     { 
      #>Render your code here<# 
     } 
    } 
#> 

अपना आउटपुट कोड रखें जहां कोड स्निपेट कहता है "यहां अपना कोड प्रस्तुत करें"।

+0

यह वास्तव में मीठा है! आपकी मदद के लिए धन्यवाद। – Alwyn

+0

यह विजुअल स्टूडियो के बिना कैसे व्यवहार करता है (यानी केवल बिल्ड सर्वर पर, केवल एमएसबिल्ड का उपयोग करके)? – julealgon

+0

मैं चाहता हूं इस कोड को विजुअल स्टूडियो के बिना काम करने की उम्मीद न करें।विजुअल स्टूडियो चल रहा है और टेम्पलेट के लिए मेजबान प्रदान करता है जब कोई केवल EnvDTE CodeModel तक पहुंच सकता है। हालांकि, अगर आपको वीएस के बिना एनवीडीटीई एक्सेस करने के लिए तर्क को तुरंत चालू करने का एक और तरीका मिल गया है, तो कोई भी इस कोड को काम करने के लिए प्राप्त कर सकता है ... मुझे खेद है। – Nico

0

मुझे ऐसा करने का एकमात्र तरीका यह है कि कुछ कोड पार्सिंग क्षमता का उपयोग करना है। मैं अपने सिर के शीर्ष से एक रास्ता नहीं सोच सकता कि यह कैसे करें। मुझे यकीन है कि .NET में कुछ उपयोगिताएं हैं जो ऐसा कर सकती हैं।

मुझे यकीन नहीं है कि आपकी स्थिति क्या है, लेकिन आम तौर पर कोड पढ़ने के बजाय, आपके पास कुछ केंद्रीकृत जानकारी है, चाहे वह एक एक्सएमएल फ़ाइल हो या कुछ यूएमएल आरेख (क्लास आरेख भी) जिसका उपयोग कोड उत्पन्न करने के लिए किया जाता है । यह चीजों को थोड़ा सा सरल बनाता है और परिवर्तन करना आसान बनाता है और कोड पीढ़ी को बदलावों को थूकने देता है। विजुअल स्टूडियो के लिए Tangible T4 टूल पर नज़र डालें।

+0

उह - वह बदसूरत होगा :(कुछ साफ चाल के लिए उम्मीद कर रहे हैं – Alwyn

6

किसी भी भावी पाठकों के लिए टी 4 विजुअलस्टूडियो हेल्पर टेम्पलेट को काम करने और प्राप्त करने के मूड में नहीं, नीचे एक स्व-निहित टेम्पलेट है जो वर्तमान प्रोजेक्ट में सभी कक्षाओं को दर्शाता है। यह विजुअल स्टूडियो 2013 में परीक्षण किया गया है और T4 Site

<#@ template debug="true" hostSpecific="true" #> 
<#@ output extension=".cs" #> 
<#@ Assembly Name="System.Core" #> 
<#@ assembly name="EnvDte" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.IO" #> 
<#@ import namespace="System.Diagnostics" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Collections" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#  
    foreach(var ns in GetNamespaceElements()) 
    { 
    foreach(var cc in ns.Members.OfType<EnvDTE.CodeClass>()) 
    { 
#>Render your code here<# 
    } 
    } 
#> 

<#+ 
    public IEnumerable<EnvDTE.CodeNamespace> GetNamespaceElements() 
    { 
    var visualStudio = (this.Host as IServiceProvider).GetService(typeof(EnvDTE.DTE)) 
         as EnvDTE.DTE; 
    var project = visualStudio.Solution.FindProjectItem(this.Host.TemplateFile) 
        .ContainingProject as EnvDTE.Project; 

    var projItems = new List<EnvDTE.ProjectItem>(); 
    FillProjectItems(project.ProjectItems, projItems); 
    var names = new HashSet<string>(projItems 
     .Where(i => i.FileCodeModel != null) 
     .SelectMany(i => i.FileCodeModel.CodeElements.OfType<EnvDTE.CodeElement>()) 
     .Where(e => e.Kind == EnvDTE.vsCMElement.vsCMElementNamespace) 
     .Select(e => e.FullName)); 

    var codeNs = new List<EnvDTE.CodeNamespace>(); 
    FillCodeNamespaces(project.CodeModel.CodeElements.OfType<EnvDTE.CodeNamespace>(), codeNs); 

    return codeNs.Where(ns => names.Contains(ns.FullName)); 
    } 

    public void FillCodeNamespaces(IEnumerable<EnvDTE.CodeNamespace> parents, List<EnvDTE.CodeNamespace> all) 
    { 
    foreach (var parent in parents) 
    { 
     all.Add(parent); 
     FillCodeNamespaces(parent.Members.OfType<EnvDTE.CodeNamespace>(), all); 
    } 
    } 

    public void FillProjectItems(EnvDTE.ProjectItems items, List<EnvDTE.ProjectItem> ret) 
    { 
    if (items == null) return; 
    foreach(EnvDTE.ProjectItem item in items) 
    { 
     ret.Add(item); 
     FillProjectItems(item.ProjectItems, ret); 
    } 
    } 
#>