Я пытаюсь создать несколько командлетов PowerShell на C# и создал класс DataChunk для хранения двоичных данных. Он просто содержит массив byte[]. Целью было прочитать байты из файла в DataChunk, чтобы показать ему, как мне это нужно. Итак, я написал метод ToString(). Но похоже, что PowerShell его не использует. Почему?
PS> $data = Read-BinaryData test.bin
PS> $data.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False DataChunk System.Object
Это то, что мне нужно:
PS> $data.ToString()
07 65 20 AE F6 8D 4F 00 97 A8 33 C9 81 EB 80 AE 92 87 7D 08
Вот как это работает сейчас:
PS> $data
Count
-----
20
Класс простой:
public class DataChunk
{
byte[] data;
public int Count => data.Length;
public override string ToString() { ... }
}
Как сделать так, чтобы мой собственный класс отображался в PowerShell так, как мне нужно?





Вы можете определить свои собственные данные формата для своего типа, см. о Format.ps1xml . В этом случае вы можете использовать CustomControl с тегом ExpressionBinding.
Сначала вам нужно определить ps1xml и сохранить его в файле, в этом примере файл сохраняется в текущем местоположении с именем DataChunk.format.ps1xml:
Set-Content DataChunk.Format.ps1xml -Value @'
<Configuration>
<ViewDefinitions>
<View>
<Name>MyCustomTestView</Name>
<ViewSelectedBy>
<TypeName>DataChunk</TypeName>
</ViewSelectedBy>
<CustomControl>
<CustomEntries>
<CustomEntry>
<CustomItem>
<ExpressionBinding>
<ScriptBlock>
$_.ToString()
</ScriptBlock>
</ExpressionBinding>
</CustomItem>
</CustomEntry>
</CustomEntries>
</CustomControl>
</View>
</ViewDefinitions>
</Configuration>
'@
Затем вам необходимо обновить данные формата для вашего пользовательского типа, используя этот файл:
Update-FormatData -PrependPath .\DataChunk.format.ps1xml
И, наконец, вы можете это проверить:
Add-Type @'
using System;
public class DataChunk
{
private readonly byte[] _data;
public int Count => _data.Length;
public DataChunk(byte[] bytes) => _data = bytes;
public override string ToString() => BitConverter.ToString(_data).Replace('-',' ');
}
'@
$bytes = 7, 101, 32, 174, 246, 141
[DataChunk]::new($bytes)
# Should output:
#
# 07 65 20 AE F6 8D
Здесь стоит отметить: если вы разрабатываете двоичный модуль, вместо обновления данных формата вручную вы должны добавить путь к файлу format.ps1xml в манифест вашего модуля (.psd1) в элементе FormatsToProcess.
Полезный ответ Сантьяго предлагает лучшее решение вашей проблемы.
Чтобы ответить на ваш вопрос:
Но похоже, что PowerShell его не использует [
.ToString()]. Почему?
Поскольку ваш тип DataChunk .NET имеет по крайней мере одно общедоступное свойство, оно обрабатывается системой PowerShell для отображения вывода.
[bool] и [char]) и типы без (публичных) свойств визуализируются через возвращаемое значение их .ToString() методов.Любой экземпляр непримитивного типа с хотя бы одним общедоступным свойством, тип которого не имеет данных форматирования, связанных с ним (пример таких данных форматирования находится в ответе Сантьяго), приводит к рендерингу объекта по его свойствам, это то, что вы испытали.
Специальный обходной путь, который заставляет использовать метод .ToString() вашего типа - помимо явного вызова этого метода - заключается в использовании интерполяции строк PowerShell, то есть расширяемой строки ("..."):
# Short alternative to:
# $data.ToString()
# $data | ForEach-Object ToString
"$data"
Я знал, что форматирование с помощью ps1xml поможет, но не понимал, почему ToString() не работает. Теперь да. Большое спасибо!