Certo, è possibile definire un tipo in Powershell e usarlo in serializzazione.
Il primo passaggio è la definizione di un nuovo tipo. In Powershell 2.0, è possibile farlo tramite chiamando il numero Add-Type. Una volta ottenuto l'assembly compilato dinamicamente contenente il nuovo tipo, è possibile utilizzare liberamente il tipo, come qualsiasi altro tipo .NET.
Fase 2 è usare solo la classe XmlSerializer, come si farebbe normalmente - basta tradurre il codice C# che hai fornito nella domanda di PowerShell.
Il seguente esempio illustra. Definisce un tipo semplice, quindi deserializza da una stringa XML per creare una nuova istanza di quel tipo. Quindi stampa i valori delle proprietà su quell'istanza de-serializzata.
$source1 = @"
using System;
using System.Xml;
using System.Xml.Serialization;
namespace MyDynamicTypes
{
[XmlRoot]
public class Foo
{
[XmlElement]
public string Message { get; set; }
[XmlAttribute]
public int Flavor { get; set; }
}
}
"@
Add-Type -TypeDefinition $source1 -Language "CSharpVersion3" -ReferencedAssemblies System.Xml.dll
$xml1 = @"
<Foo Flavor='19'>
<Message>Ephesians 5:11</Message>
</Foo>
"@
$f1 = New-Object MyDynamicTypes.Foo
$sr = New-Object System.IO.StringReader($xml1)
$s1 = New-Object System.Xml.Serialization.XmlSerializer($f1.GetType())
$xtr = New-Object System.Xml.XmlTextReader($sr)
$foo = $s1.Deserialize($xtr)
Write-Output ("foo.Flavor = " + $foo.Flavor)
Write-Output ("foo.Message = " + $foo.Message)
Grazie a Keith Hill per indicare Add-Type out.
in PowerShell 1.0, si può fare qualcosa di simile con un po 'di codice personalizzato (vedi Powershell: compiling c# code stored in a string).
function Compile-Code {
param (
[string[]] $code = $(throw "The parameter -code is required.")
, [string[]] $references = @()
, [switch] $asString = $false
, [switch] $showOutput = $false
, [switch] $csharp = $true
, [switch] $vb = $false
)
$options = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]";
$options.Add("CompilerVersion", "v3.5")
if ($vb) {
$provider = New-Object Microsoft.VisualBasic.VBCodeProvider $options
} else {
$provider = New-Object Microsoft.CSharp.CSharpCodeProvider $options
}
$parameters = New-Object System.CodeDom.Compiler.CompilerParameters
@("mscorlib.dll", "System.dll", "System.Core.dll", "System.Xml.dll", ([System.Reflection.Assembly]::GetAssembly([PSObject]).Location)) + $references | Sort -unique |% { $parameters.ReferencedAssemblies.Add($_) } | Out-Null
$parameters.GenerateExecutable = $false
$parameters.GenerateInMemory = !$asString
$parameters.CompilerOptions = "/optimize"
if ($asString) {
$parameters.OutputAssembly = [System.IO.Path]::GetTempFileName()
}
$results = $provider.CompileAssemblyFromSource($parameters, $code)
if ($results.Errors.Count -gt 0) {
if ($output) {
$results.Output |% { Write-Output $_ }
} else {
$results.Errors |% { Write-Error $_.ToString() }
}
} else {
if ($asString) {
$content = [System.IO.File]::ReadAllBytes($parameters.OutputAssembly)
$content = [Convert]::ToBase64String($content)
[System.IO.File]::Delete($parameters.OutputAssembly);
return $content
} else {
return $results.CompiledAssembly
}
}
}
Usando questa funzione, l'applicazione diventa:
$source1 = @"
using System;
using System.Xml;
using System.Xml.Serialization;
namespace MyDynamicTypes
{
[XmlRoot]
public class Foo
{
[XmlElement]
public string Message { get; set; }
[XmlAttribute]
public int Flavor { get; set; }
}
}
"@
Compile-Code -csharp -code $source1
$xml1 = @"
<Foo Flavor='19'>
<Message>Ephesians 5:11</Message>
</Foo>
"@
$f1 = New-Object MyDynamicTypes.Foo
$sr = New-Object System.IO.StringReader($xml1)
$s1 = New-Object System.Xml.Serialization.XmlSerializer($f1.GetType())
$xtr = New-Object System.Xml.XmlTextReader($sr)
$foo = $s1.Deserialize($xtr)
Write-Output ("foo.Flavor = " + $foo.Flavor)
Write-Output ("foo.Message = " + $foo.Message)
e dove si vorrebbe 'MyType' se non da un assieme? Non è possibile definire direttamente i tipi in PowerShell; devo usare 'Aggiungi tipo 'per quello. – Joey
Questa è esattamente la mia domanda: esiste un modo per definire in qualche modo il tipo in PowerShell e quindi utilizzarlo per la serializzazione? Sulla base della risposta, non sembra, quindi, devono definire i tipi in un assembly ... Che dolore - volevo creare un'intera soluzione basata su script per un problema senza richiedere assemblaggi et al. Grazie. – Ariel
"c'è un modo semplice, come XmlSerializer, per serializzare i tipi in PowerShell" Import/Export-CliXml dovrebbe funzionare bene. – stej