Domanda

Vorrei i file generati dal mio strumento personalizzato da nascondere, ma non riesco a trovare alcuna documentazione su come questo viene fatto.

Un esempio di quello che sto cercando è il codice WPF dietro file. Questi file non vengono visualizzati in Visual Studio vista del progetto, ma sono compilati con il progetto e sono disponibili in IntelliSense. Codice WPF dietro file (Window1.g.i.cs, per esempio), sono generati da uno strumento personalizzato.

È stato utile?

Soluzione

La soluzione è quella di creare un obiettivo che aggiunge i file alla compilazione ItemGroup piuttosto che aggiungere in modo esplicito nel file Csproj. In questo modo Intellisense li vedrà e saranno compilati nel vostro eseguibile, ma non verrà visualizzato in Visual Studio.

Esempio semplice

È inoltre necessario assicurarsi che il vostro obiettivo è aggiunto alla proprietà CoreCompileDependsOn in modo che eseguirà prima dell'esecuzione del compilatore.

Ecco un esempio estremamente semplice:

<PropertyGroup>
  <CoreCompileDependsOn>$(CoreCompileDependsOn);AddToolOutput</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="HiddenFile.cs" />
  </ItemGroup>
</Target>

Se si aggiunge questo alla parte inferiore del vostro CSPROJ (poco prima </Project>), il vostro "HiddenFile.cs" sarà incluso nella compilation, anche se non appare in Visual Studio.

Utilizzo di un file .targets separata

Invece di mettere questo direttamente nel tuo Csproj file, voi generalmente collocato in un .targets separati File circondato da:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  ...
</Project>

e l'importazione nel vostro .csproj con <Import Project="MyTool.targets">. Un file .targets è consigliato anche per una tantum casi perché separa il codice personalizzato dalla roba in Csproj che è gestito da Visual Studio.

Costruire il nome del file generato (s)

Se si sta creando uno strumento generalizzate e / o utilizzando un file .targets separata, probabilmente non si vuole elencare esplicitamente ogni file nascosto. Invece si desidera generare i nomi dei file nascosti da altre impostazioni nel progetto. Per esempio, se si desidera che tutti i file di risorse di avere corrispondenti file di utensili generati nella directory "obj", il vostro obiettivo potrebbe essere:

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="@(Resource->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
  </ItemGroup>
</Target>

La proprietà "IntermediateOutputPath" è ciò che tutti sappiamo come directory "obj", ma se l'utente finale dei vostri .targets ha personalizzato questo i file intermedi sarà stil essere trovati nello stesso luogo. Se preferite i file generati per essere nella directory principale del progetto e non nella directory "obj", si può lasciare fuori questo.

Se desideri solo alcuni dei file di un tipo di elemento esistente da lavorare dal vostro strumento personalizzato? Ad esempio, si può decidere di generare file per tutti i file Page e di risorse con estensione "xyz".

<Target Name="AddToolOutput">
  <ItemGroup>
    <MyToolFiles Include="@(Page);@(Resource)" Condition="'%(Extension)'=='.xyz' />
    <Compile Include="@(MyToolFiles->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')"/>
  </ItemGroup>
</Target>

Si noti che non è possibile utilizzare la sintassi dei metadati come% (Extension) in un top-level ItemGroup ma è possibile farlo entro un bersaglio.

Utilizzo di un tipo di elemento personalizzato (aka costruire Azione)

I file processi di cui sopra che hanno un tipo di elemento esistente, ad esempio pagine, risorse, o compilare (Visual Studio chiama "Operazione di generazione"). Se i vostri articoli sono un nuovo tipo di file che è possibile utilizzare il proprio tipo di elemento personalizzato. Per esempio, se i file di input sono chiamati file "XYZ", il file di progetto possono definire "XYZ" come un tipo di elemento valido:

<ItemGroup>
  <AvailableItemName Include="Xyz" />
</ItemGroup>

dopo di che Visual Studio vi permetterà di selezionare "XYZ" in azione Costruire nelle proprietà del file, con conseguente questo essere aggiunto al tuo .csproj:

<ItemGroup>
  <Xyz Include="Something.xyz" />
</ItemGroup>

Ora è possibile utilizzare la "XYZ" tipo di elemento per creare i nomi dei file per l'uscita strumento, proprio come abbiamo fatto in precedenza con la "risorsa" tipo di elemento:

<Target Name="AddToolOutput">
  <ItemGroup>
    <Compile Include="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')" />
  </ItemGroup>
</Target>

Quando si usa un tipo di elemento personalizzato è possibile causare i tuoi articoli ad essere effettuato anche con built-in meccanismi per la mappatura ad un altro tipo di elemento (aka costruire azione). Questo è utile se i file "XYZ" sono in realtà file Cs o XAML o se hanno bisogno di essere fatte

EmbeddedResources. Per esempio è possibile causare tutti i file con "Operazione di generazione" di Xyz per anche essere compilato:

<ItemGroup>
  <Compile Include="@(Xyz)" />
</ItemGroup>

Se i file di origine "XYZ" devono essere conservati come risorse incorporate, è possibile esprimere in questo modo:

<ItemGroup>
  <EmbeddedResource Include="@(Xyz)" />
</ItemGroup>

Si noti che il secondo esempio non funziona se lo metti dentro la destinazione, dal momento che l'obiettivo non è valutato fino a poco prima della compilazione del nucleo. Per fare questo lavoro all'interno di un bersaglio che deve elencare il nome di destinazione in PrepareForBuildDependsOn proprietà invece di CoreCompileDependsOn.

Invocare la tuageneratore di codice personalizzato da MSBuild

Dopo aver andato per quanto riguarda la creazione di un file .targets, si potrebbe considerare invocando il vostro strumento direttamente da MSBuild piuttosto che utilizzare un evento di pre-compilazione separata o un meccanismo di Visual Studio imperfetto "strumento personalizzato".

Per fare questo:

  1. Creare un progetto Libreria di classi con un riferimento a Microsoft.Build.Framework
  2. Aggiungi il codice per implementare il generatore di codice personalizzato
  3. Aggiungi una classe che implementa ITask, e nel metodo Execute chiamare il codice personalizzato generatore
  4. Aggiungi un elemento UsingTask al file .targets, e nel vostro target aggiungere una chiamata alla vostra nuova attività

Ecco tutto quello che devi implementare ITask:

public class GenerateCodeFromXyzFiles : ITask
{
  public IBuildEngine BuildEngine { get; set; }
  public ITaskHost HostObject { get; set; }

  public ITaskItem[] InputFiles { get; set; }
  public ITaskItem[] OutputFiles { get; set; }

  public bool Execute()
  {
    for(int i=0; i<InputFiles.Length; i++)
      File.WriteAllText(OutputFiles[i].ItemSpec,
        ProcessXyzFile(
          File.ReadAllText(InputFiles[i].ItemSpec)));
  }

  private string ProcessXyzFile(string xyzFileContents)
  {
    // Process file and return generated code
  }
}

E qui è l'elemento UsingTask e un obiettivo che lo chiama:

<UsingTask TaskName="MyNamespace.GenerateCodeFromXyzFiles" AssemblyFile="MyTaskProject.dll" />


<Target Name="GenerateToolOutput">

  <GenerateCodeFromXyzFiles
      InputFiles="@(Xyz)"
      OutputFiles="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

    <Output TaskParameter="OutputFiles" ItemGroup="Compile" />

  </GenerateCodeFromXyzFiles>
</Target>

Si noti che elemento di uscita di questo obiettivo pone l'elenco dei file di output direttamente in compilazione, quindi non c'è alcuna necessità di utilizzare un ItemGroup separato per fare questo.

Come il vecchio meccanismo di "strumento personalizzato" è viziata e perché non usarlo

Una nota riguardo il meccanismo di "strumento personalizzato" di Visual Studio: In NET Framework 1.x non avevamo MSBuild, così abbiamo dovuto fare affidamento su Visual Studio per costruire i nostri progetti. Al fine di ottenere Intellisense sul codice generato, Visual Studio ha avuto un meccanismo chiamato "strumento personalizzato" che può essere impostato nella finestra Proprietà su un file. Il meccanismo è stato fondamentalmente errata in diversi modi, che è il motivo per cui è stato sostituito con gli obiettivi di MSBuild. Alcuni dei problemi con la funzione "strumento personalizzato" erano:

  1. A "strumento personalizzato" costruisce il file generato ogni volta che il file viene modificato e salvato, non quando il progetto viene compilato. Ciò significa che tutto ciò che modificano il file esternamente (come ad esempio un sistema di controllo di revisione) non aggiorna il file generato e spesso si ottiene il codice stantio nel vostro eseguibile.
  2. L'uscita di uno "strumento personalizzato" doveva essere fornito con la struttura di origine a meno che il destinatario ha avuto anche Visual Studio e il tuo "strumento personalizzato".
  3. Il "strumento personalizzato" doveva essere installato nel Registro di sistema e non poteva essere semplicemente riferimento dal file di progetto.
  4. L'uscita del "strumento personalizzato" non viene memorizzato nella directory "obj".

Se si utilizza la vecchia funzione di "strumento personalizzato", mi consiglia di passare all'utilizzo di un compito MSBuild. Funziona bene con Intellisense e ti permette di costruire il vostro progetto senza nemmeno installare Visual Studio (tutto ciò che serve è .NET Framework).

Quando sarà la vostra abitudine di esecuzione dell'attività di costruzione?

In generale il vostro compito di generazione personalizzata verrà eseguita:

  • In sottofondo quando Visual Studio apre la soluzione, se il file generato non è aggiornata
  • In fondo ogni volta che si salva un file di input in Visual Studio
  • Ogni volta che si genera, se il file generato non è aggiornato
  • Ogni volta che si ricostruisce

Per essere più precisi:

  1. Un IntelliSense generazione incrementale viene eseguito quando si avvia Visual Studio e ogni volta che un file viene salvato all'interno di Visual Studio. Questo verrà eseguito il generatore se il file di output manca uno qualsiasi dei file di input sono più recente rispetto alla uscita del generatore.
  2. Una generazione incrementale regolare viene eseguito ogni volta che si utilizza qualsiasi comando "Esegui" "costruire" o in Visual Studio (comprese le opzioni di menu e premendo F5), o quando si esegue "MSBuild" dalla riga di comando. Come la generazione incrementale IntelliSense, sarà anche eseguito solo il generatore se il file generato non è aggiornato
  3. Un regolare generazione completa viene eseguito ogni volta che si utilizza uno dei "Rebuild" comandi in Visual Studio, o quando si esegue "MSBuild / t: Rebuild" dalla riga di comando. Sarà sempre eseguito il generatore se ci sono ingressi o uscite.

Si può decidere di forzare il generatore per eseguire in altri momenti, come quando alcuni cambiamenti variabili ambiente, o costringerlo a funzionare in modo sincrono piuttosto nel backgtondo.

  • Per provocare il generatore di ri-eseguire anche quando nessun file di input sono cambiati, il modo migliore è di solito per aggiungere un ingresso aggiuntivo per il vostro obiettivo che è un file di input fittizio memorizzato nella directory "obj". Poi ogni volta che una variabile d'ambiente o di alcuni cambiamenti di impostazione esterni che dovrebbero forzare il tuo strumento generatore di re-run, è sufficiente toccare questo file (es. Creare o aggiornare la propria data di modifica).

  • Per forzare il generatore per eseguire in modo sincrono, piuttosto che in attesa di IntelliSense per l'esecuzione in background, basta usare MSBuild per costruire il vostro obiettivo particolare. Questo potrebbe essere semplice come l'esecuzione di "MSBuild / t: GenerateToolOutput", o VSIP può fornire un build-in modo di chiamare gli obiettivi di generazione personalizzata. In alternativa si può semplicemente richiamare il comando Costruire e attendere la fine del processo.

Si noti che "I file di input" in questo capitolo si riferisce a tutto ciò che è elencato nella attributo "ingressi" dell'elemento di destinazione.

Note finali

Si può ottenere avvertimenti da parte di Visual Studio che non sa se fidarsi di file strumento personalizzato .targets. Per risolvere questo problema, aggiungerlo alla chiave HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ VisualStudio \ 9.0 \ MSBuild \ SafeImports chiave di registro.

Ecco un riassunto di ciò che un file .targets effettivi sarebbe simile con tutti i pezzi a posto:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <CoreCompileDependsOn>$(CoreCompileDependsOn);GenerateToolOutput</CoreCompileDependsOn>
  </PropertyGroup>

  <UsingTask TaskName="MyNamespace.GenerateCodeFromXyzFiles" AssemblyFile="MyTaskProject.dll" />


  <Target Name="GenerateToolOutput" Inputs="@(Xyz)" Outputs="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

    <GenerateCodeFromXyzFiles
        InputFiles="@(Xyz)"
        OutputFiles="@(Xyz->'$(IntermediateOutputPath)%(FileName)%(Extension).g.cs')">

      <Output TaskParameter="OutputFiles" ItemGroup="Compile" />

    </GenerateCodeFromXyzFiles>
  </Target>

</Project>

Per favore fatemi sapere se avete domande o c'è qualcosa qui non hai capito.

Altri suggerimenti

Per nascondere gli elementi da Visual Studio aggiungere un alloggio metadati Visible alla voce. I metadati InProject fa a quanto pare anche questo.

Visibile: http://msdn.microsoft.com /en-us/library/ms171468(VS.90).aspx

Inproject: http: //blogs.msdn. com / b / jomo_fisher / archive / 2005/01/25 / 360302.aspx

<ItemGroup>
  <Compile Include="$(AssemblyInfoPath)">
    <!-- either: -->
    <InProject>false</InProject>
    <!-- or: -->
    <Visible>false</Visible>
  </Compile>
</ItemGroup>

L'unico modo che conosco per farlo è quello di aggiungere il file generato di avere una dipendenza sul file che si desidera nascosto dietro -. Nel file proj

Ad esempio:

 <ItemGroup>
    <Compile Include="test.cs" />
    <Compile Include="test.g.i.cs">
      <DependentUpon>test.cs</DependentUpon>
    </Compile>
  </ItemGroup>

Se è stato rimosso l'elemento DependentUpon poi risulta dal fascicolo accanto all'altro file invece di dietro di esso ... come fa il vostro generatore di aggiungere i file? ci puoi camminare attraverso il caso d'uso e come si vorrebbe che al lavoro?

Credo che si vuole guardare qui: http://msdn.microsoft .com / it-it / library / ms171453.aspx .

In particolare, la "Creazione di prodotti che durante l'esecuzione" sezione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top