1

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

我想知道的是我是否能够管道我自己的类型,以便我可以在命运过程中轻松检索它们。我期望的是做类似的事情:

myProgram | get-member

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

这在控制台应用程序中是否可行,还是我只能使用 cmdlet 来实现?

4

2 回答 2

3

最简单的方法是使用序列化将您希望从一个发送到另一个的对象转换为可管道格式以将它们从一个发送到另一个。但是,这样做有一些限制:

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

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

    public string TestAgain { get; set; }

    public string Cheese { get; set; }
}

[Serializable] 属性将其标记为可序列化,这对于简单的类来说已经足够了。对于更复杂的类,可能需要更多 - 请参阅 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 及其周围的文档应该会给你剩下的。

于 2013-01-25T04:56:06.743 回答
1

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

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

于 2013-01-25T04:46:28.640 回答