2017-12-24 26 views
2

Ich versuche, Dictionary oder Hashtable zwischen MSBuild Aufgaben zu senden/teilen.Hashtable/Dictionary-Parameter in MSBuild Aufgabe

Ich habe die folgenden zwei benutzerdefinierten Aufgaben, Get, die eine Hashtable und Set erzeugt, die es verbrauchen sollte.

Get.cs

public class Get : Task 
{ 
    [Output] 
    public Hashtable Output { get; set; } 

    public override bool Execute() 
    { 
     Output = new Hashtable(); 
     return true; 
    } 
} 

Set.cs

public class Set : Task 
{ 
    [Required] 
    public Hashtable Output { get; set; } 

    public override bool Execute() 
    { 
     var items = Output.Cast<DictionaryEntry>().ToDictionary(d => d.Key.ToString(), d => d.Value.ToString()); 

     foreach(var item in items) 
     { 
      //Do Something 
     } 

     return true; 
    } 
} 

Die oben genannten Klassen bauen fein in Assembly.dll

ich dann, dass in der folgenden Build-Ziel-Skript verwenden Assembly.dll um die benutzerdefinierten Tasks Get und Set aufzurufen:

MyTarget.targets

<?xml version="1.0" encoding="utf-8"?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask TaskName="Get" AssemblyFile=".\Assembly.dll"/> 
    <UsingTask TaskName="Set" AssemblyFile=".\Assembly.dll"/> 

    <Target Name="Get"> 

    <Get> 
     <Output TaskParameter="Output" ItemName="Output" /> 
    </Get> 
    <Set [email protected](Output) /> 

    </Target> 

</Project> 

Als ich das Projekt mit dem obigen Ziel MSBuild zeigt die folgenden Fehler bauen:

The "System.Collections.Hashtable" type of the "Output" parameter of the "Get" task is not supported by MSBuild

Wie kann ich eine Hashtable oder Dictionary in einer Eigenschaft für eine benutzerdefinierte MSBuild-Aufgabe?

Antwort

3

Die Parameter, die in eine Task hinein oder heraus gehen können, sind auf ITaskItem oder ein Array von ITaskItem beschränkt.

So sollten Sie Ihre Eigenschaften von

ändern
public Hashtable Output { get; set; } 

zu

public ITaskItem[] Output { get; set; } 

dieser Anforderung zu entsprechen.

Als nächstes benötigen Sie eine Implementierungsklasse, die ITaskItem implementiert. Damit können Sie mit Ihrem Hashset oder Wörterbuch umgehen. Ich verließ das für Sie, dass hinzufügen, aber eine minimale KeyValue Klasse könnte wie folgt aussehen:

public class KeyValue: ITaskItem 
{ 
    string _spec = String.Empty; 

    public KeyValue(string key, string value) 
    { 
     _spec = key; 
     metadata.Add("value", value); 
    } 

    Dictionary<string,string> metadata = new Dictionary<string,string>(); 

    public string ItemSpec 
    { 
     get {return _spec;} 
     set {} 
    } 
    public ICollection MetadataNames 
    { 
     get {return metadata.Keys;} 
    } 
    public int MetadataCount 
    { 
     get {return metadata.Keys.Count;} 
    } 
    public string GetMetadata(string metadataName) 
    { 
     return metadata[metadataName]; 
    } 
    public void SetMetadata(string metadataName, string metadataValue) 
    { 
     metadata[metadataName] = metadataValue; 
    } 
    public void RemoveMetadata(string metadataName) 
    { 
    } 
    public void CopyMetadataTo(ITaskItem destinationItem) 
    { 
    } 
    public IDictionary CloneCustomMetadata() 
    { 
      return metadata; 
    } 
} 

Diese Klasse wird produzieren und Artikel, die aussehen aussehen wird, wenn es in der Ebene MSBuild-Skript fertig war:

<Item Include="key"> 
    <value>some value</value> 
</Item> 

nächstes können Sie die Set und Get-Task anpassen diese neue Klasse KeyValue zu verwenden:

public class Set : Task 
{ 

    TaskLoggingHelper log; 

    public Set() { 
     log = new TaskLoggingHelper(this); 
    } 

    [Required] 
    public ITaskItem[] Output { get; set; } 

    public override bool Execute() 
    { 
     log.LogMessage("start set"); 
     foreach(var item in Output) 
     { 
      log.LogMessage(String.Format("Set sees key {0} with value {1}.",item.ItemSpec, item.GetMetadata("value"))); 
     } 
     log.LogMessage("end set"); 
     return true; 
    } 
} 

public class Get : Task 
{ 

    // notice this property no longer is called Output 
    // as that gave me errors as the property is reserved  
    [Output] 
    public ITaskItem[] Result { get; set; } 

    public override bool Execute() 
    { 
     // convert a Dictionary or Hashset to an array of ITaskItems 
     // by creating instances of the class KeyValue. 
     // I use a simple list here, I leave it as an exercise to do the other colletions 
     Result = new List<ITaskItem> { new KeyValue("bar", "bar-val"), new KeyValue("foo","foo val") }.ToArray(); 
     return true; 
    } 
} 

die Build-Datei, die ich über Code zu testen:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask TaskName="Get" AssemblyFile=".\cb.dll"/> 
    <UsingTask TaskName="Set" AssemblyFile=".\cb.dll"/> 

    <Target Name="Get"> 

    <Get> 
     <Output TaskParameter="Result" ItemName="GetResult" /> 
    </Get> 

    <!-- lets see what we've got --> 
    <Message Importance="high" Text="key: @(GetResult) :: value: %(value)" /> 

    <Set Output="@(GetResult)"> 

    </Set> 

    </Target> 

</Project> 

Wenn das Ergebnis ausgeführt wird:

Build started 24-12-2017 21:26:17. 
Project "C:\Prj\bld\test.build" on node 1 (default targets). 
Get: 
    key: bar :: value: bar-val 
    key: foo :: value: foo val 
    start set 
    Set sees key bar with value bar-val. 
    Set sees key foo with value foo val. 
    end set 
Done Building Project "C:\Prj\bld\test.build" (default targets). 


Build succeeded. 
    0 Warning(s) 
    0 Error(s) 
Verwandte Themen