2011-03-18 61 views
7

我有一些数据,我从一个数据源获得的是一串名称/值对,我存储在一个字典<字符串,对象>。如何在C#中PowerShell Cmdlet的动态定义类

我想动态地定义一个类,其属性映射到字典中的键/值对和基于它所表示的数据类型的方法。这将允许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 ... 

我该如何处理自己的物体?

UPDATE

接受基思的答案是动态生成代码的通用.NET框架的方法。这应该适用于我的场景,尽管我认为这可能是矫枉过正。

我曾希望有人会提供一个使用PowerShell提供的工具来完成此操作的明确示例。看起来应该有一种方法可以通过扩展Powershell SDK中描述的PSObject,PSPropertyPSMethod类来动态创建类。

不幸的是,围绕这个的文档似乎很差,有很多荒谬的陈述,比如“尽管可以从这个类派生,但是没有确定的方案来做到这一点,并且任何尝试这样做都可能导致意外的行为

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

你好,任何来自PowerShell团队的人都在听吗?

回答

3

看一看System.Reflection.Emit namespace。这将允许您在运行时生成代码。 System.AppDomain有一些称为DefineDynamicAssembly的重载,这通常是您要启动的位置。这将返回一个AssemblyBuilder,并从那里使用类型如TypeBuilderPropertyBuilder,MethodBuilder等。此CodeProject article是创建具有反射发射的动态类型的体面入门书。

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 

如果你不需要的东西太复杂,你也许可以采取“泼洒”的优势 - 通常这是用于生产的名称/值对传递给cmdlet的或功能,但它也可以作为一种通用对象:

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

PS H:\> $splat 

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

我正在寻找一种方法来从使用PowerShell SDK编写的C#Cmdlet中执行此操作。 – DSO 2011-03-18 19:25:12

+0

刚刚经过测试 - 你可以在splats中为* values *设置不同的类型,这可能有用。 – Neolisk 2013-04-12 12:14:29

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

还有功能模拟psclasses,这是说,你起订量的所有漂亮的功能与动态psobject。

+0

尽管该项目还活着,但这些链接似乎已经死亡。 – 2015-04-07 14:58:16

+1

谢谢,是的,我已将模块套件更名为Aether *。更新链接。 – wesm 2015-04-08 16:20:55