如何在 C# 控制台应用中管道自定义类型(类似于 Powershell)

本文关键字:类型 自定义 类似于 Powershell 管道 控制台 应用 | 更新日期: 2023-09-27 17:56:02

我知道我能够使用简单的Console.WriteLine和Console.ReadLine方法管道输出/传入,但这样我在进程之间传递一个字符串(必须解析该字符串才能重新创建对象)。

想知道的是,我是否能够管道化我自己的类型,以便我可以在命运过程中轻松检索它们。我期望的是执行以下操作:

myProgram | get-member

输出类似于MyNameSpace.MyType及其成员列表(当前它显示typeName System.String)

这在控制台应用中是否可行,或者我只能使用 cmdlet 实现此目的?

如何在 C# 控制台应用中管道自定义类型(类似于 Powershell)

最简单的方法是使用序列化将要从一个对象发送到另一个对象转换为可管道格式,以便将它们从一个对象发送到另一个对象。 但是,这样做存在许多限制:

首先,来回传递的类型实现必须可用于可能处理它们的所有应用。 (这对 PowerShell 来说不是问题,因为所有 cmdlet 都在同一进程中运行。 因此,执行此操作的最简单方法是创建要在所有控制台应用引用的类库中传送的类型。 例如,这个类,我放在我的示例共享库中:

[Serializable]
public class TestClass
{
    public string Test { get; set; }
    public string TestAgain { get; set; }
    public string Cheese { get; set; }
}

[可序列化] 属性将其标记为可序列化,这对于简单类来说已经足够了。 对于更复杂的类,可能需要更多类 - 请参阅 MSDN,从此处开始:http://msdn.microsoft.com/en-us/library/4abbf6k0(v=VS.71).aspx

然后,在你从中管道传输的程序中,你把它序列化为 XML 并将其写出到控制台,如下所示:

using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using Shared;
namespace Out
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create the object.
            TestClass test = new TestClass();
            test.Test = "Monkey";
            test.TestAgain = "Hat";
            test.Cheese = "Fish";
            // Serialize it.
            XmlSerializer serializer = new XmlSerializer(typeof (TestClass));
            StringBuilder sb = new StringBuilder();
            using (var writer = new StringWriter(sb))
                serializer.Serialize(writer, test);
            // And write it to console.
            Console.WriteLine(sb.ToString());
        }
    }
}

运行时,这将输出以 XML 编码的实例属性,因此:

<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http
://www.w3.org/2001/XMLSchema">
  <Test>Monkey</Test>
  <TestAgain>Hat</TestAgain>
  <Cheese>Fish</Cheese>
</TestClass>

然后,在接收应用程序中,您反转该过程,从控制台读取,因此:

using System;
using System.IO;
using System.Xml.Serialization;
using Shared;
namespace In
{
    class Program
    {
        static void Main(string[] args)
        {
            // Read the input XML; until complete.
            string input = Console.In.ReadToEnd();
            TestClass passedIn;
            // Deserialize it.
            var serializer = new XmlSerializer(typeof (TestClass));
            using (var reader = new StringReader(input))
                passedIn = (TestClass) serializer.Deserialize(reader);
            // Do something with the object.
            Console.WriteLine("Test:      {0}", passedIn.Test);
            Console.WriteLine("TestAgain: {0}", passedIn.TestAgain);
            Console.WriteLine("Cheese:    {0}", passedIn.Cheese);
        }
    }
}

瞧!

C:'Working'PipeExample'In'bin'Debug>..'..'..'Out'bin'Debug'Out.exe | in
Test:      Monkey
TestAgain: Hat
Cheese:    Fish

当然,您需要一些额外的代码来确保接收应用程序知道预期什么类型 - 或者可以处理它获得的任何内容 - 并且由于中间 XML 不是非常可解析的,您需要一种方法来确保发送应用程序知道它何时与管道通信以及何时与人类通信。 在 .NET 4.5 中,Console.IsOutputRedirected() 方法将为您执行此操作(http://msdn.microsoft.com/en-us/library/system.console.isoutputredirected%28v=VS.110%29.aspx),但在早期版本中,没有一种简单的方法可以通过编程方式获取此信息。

但这是事情的核心,查看 XmlSerializer 的文档应该会给你剩下的。

为什么不编写自己的 cmdlet 而不是控制台程序?

PowerShell 模块可以是二进制模块(DLL 程序集),由用 C# 编写的 cmdlet 组成。查看安装 Windows PowerShell SDK。