如何在C#PowerShell Cmdlet中动态定义类

时间:2011-03-18 17:05:20

标签: c# powershell powershell-v2.0

我从数据源获取了一些数据,这是一组名称/值对,我存储在Dictionary< string,object>中。

我想动态定义一个类,其属性映射到字典中的键/值对,以及基于它所代表的数据类型的方法。这将允许cmdlet的用户作为对象的属性访问值,并在其上调用方法。

我用Get-WmiObject看到了这个例子。它返回ManagementObject的实例(基本上是一个通用属性包),但用户可以直接访问属性并在其上调用方法(即无需在ManagementObject上调用GetPropertyValue / InvokeMethod方法)。

PS C:\temp> $comp = Get-WmiObject Win32_ComputerSystem
PS C:\temp> $comp | Get-Member

   TypeName: System.Management.ManagementObject#root\cimv2\Win32_ComputerSystem

Name                        MemberType   Definition
----                        ----------   ----------
JoinDomainOrWorkgroup       Method       System.Management.ManagementBaseObject JoinDomainO
Rename                      Method       System.Management.ManagementBaseObject Rename(Syst
SetPowerState               Method       System.Management.ManagementBaseObject SetPowerSta
UnjoinDomainOrWorkgroup     Method       System.Management.ManagementBaseObject UnjoinDomai
AdminPasswordStatus         Property     System.UInt16 AdminPasswordStatus {get;set;}
AutomaticManagedPagefile    Property     System.Boolean AutomaticManagedPagefile {get;set;}
AutomaticResetBootOption    Property     System.Boolean AutomaticResetBootOption {get;set;}
... etc ...

如何使用自己的对象执行此操作?

更新

接受Keith的答案,这是一种动态生成代码的通用.NET框架方法。这应该适用于我的场景,虽然我认为它可能有点过分。

我希望有人能够使用PowerShell提供的功能提供一个明确的示例。似乎应该有一种通过扩展PSObject中描述的PSPropertyPSMethodPowershell SDK类来动态创建类的方法。

不幸的是,围绕这个的文档看起来很糟糕,有许多荒谬的陈述,如“虽然可以从这个类派生,但是没有确定的方法可以做到这一点,任何这样做的尝试都可能导致意外行为。

更糟糕的是MSDN中解释PowerShell扩展类型系统的所有链接似乎都很糟糕!我在网上看到的唯一例子是如何从PowerShell脚本执行此操作,而不是使用C#和SDK开发cmdlet的人。

您好,PowerShell团队的任何人都在听吗?

3 个答案:

答案 0 :(得分:6)

定义自己的新类的能力是他们在PowerShell v2中添加的新功能。这是一个示例:

PS C:\> $def = @"
public class MyClass {
  public string MyProperty;
}
"@

PS C:\> Add-Type -TypeDefinition $def
PS C:\> $obj = New-Object MyClass
PS C:\> $obj.MyProperty = "Hello"
PS C:\> $obj

MyProperty
----------
Hello

如果您不需要太复杂的东西,您可能可以利用“splatting” - 通常这是为了生成用于传递给cmdlet或函数的名称/值对,但它可以作为通用的一种工作各种对象:

PS C:\> $splat = @{
  Name = "goyuix"
  Site = "stackoverflow.com"
  Tag = "powershell"
}

PS H:\> $splat

Name    Value
----    -----
Name    Goyuix
Site    stackoverflow.com
Tag     powershell

答案 1 :(得分:3)

看看System.Reflection.Emit namespace。这将允许您在运行时生成代码。 System.AppDomain有许多名为DefineDynamicAssembly的重载,通常是您要启动的地方。这会返回AssemblyBuilder,您可以使用TypeBuilderPropertyBuilderMethodBuilder等类型。CodeProject article是创建动态类型的理想入门读物反射发射。

答案 2 :(得分:0)

我一直致力于增强PSClass的实现。

实施来源: https://github.com/ghostsquad/AetherClass/blob/master/functions/New-PSClass.ps1

测试用法: https://github.com/ghostsquad/AetherClass/blob/master/test/New-PSClass.Tests.ps1

还有模拟psclass的功能,也就是说,你可以使用动态psobject获得Moq的所有漂亮功能。