如何在 C# PowerShell Cmdlet 中动态定义类
我有一些从数据源获取的数据,这些数据是我存储在 Dictionary
我想动态定义一个类,其中的属性映射到字典中的键/值对,并根据其表示的数据类型来定义方法。这将允许 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,PSProperty 和 PSMethod 类在 Powershell SDK。
不幸的是,与此相关的文档似乎相当糟糕,有很多荒谬的陈述,例如“虽然可以从此类派生,但没有建立执行此操作的场景,任何这样做的尝试都可能会导致意外的行为。< /em>”
更糟糕的是,MSDN 中解释 PowerShell 扩展类型系统的所有链接似乎都很糟糕!我在网上看到的唯一示例是如何通过 PowerShell 脚本执行此操作,而不是针对使用 C# 和 SDK 开发 cmdlet 的人员。
大家好,PowerShell 团队有人在听吗?
I have some data I'm getting from a datasource which is a bunch of name/value pairs that I store in a Dictionary<string, object>.
I want to define a class on the fly, with properties that map to the key/value pairs from the dictionary and methods based on the type of data it represents. This would allow the user of the cmdlet to access the values as properties of an object and also invoke methods on it.
I see an example of this with Get-WmiObject. It returns instances of ManagementObject (which is basically a generic property bag) but the user is able to access the properties and invoke methods on it directly (i.e. without having to call the GetPropertyValue/InvokeMethod methods on ManagementObject).
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 ...
How do I do this with my own objects?
UPDATE
Accepting Keith's answer which is a general .NET framework approach for generating code dynamically. This should work for my scenario although I think it might be overkill.
I was hoping someone would provide a clear example of doing this using the facilities provided by PowerShell. It seems there should be a way to create a class dynamically by extending the PSObject, PSProperty, and PSMethod classes described in the Powershell SDK.
Unfortunately the documentation around this seems pretty poor with a lot of ridiculous statements like "Although it is possible to derive from this class, there is no established scenario for doing this and any attempt to do so may result in unexpected behavior."
What made it worse is that all the links in MSDN explaining the PowerShell Extended Type System seem to be bad! And the only examples I've seen on the web is how to do this from a PowerShell script, not for people developing cmdlets using C# and the SDK.
Hello, anyone from the PowerShell team listening?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
定义自己的新类的能力是他们在 PowerShell v2 中添加的新功能。这是一个示例:
如果您不需要太复杂的东西,您也许可以利用“splatting” - 通常这用于生成名称/值对以传递给 cmdlet 或函数,但它可以作为一种工作方式也是一种通用对象:
The ability to define your own new classes is something new they added in PowerShell v2. Here is a sample:
If you don't need something too complex, you might be able to take advantage of "splatting" - typically this is for producing name/value pairs for passing to cmdlets or functions, but it can work as kind of a generic object of sorts too:
查看 System.Reflection.Emit 命名空间 。这将允许您在运行时生成代码。 System.AppDomain 有许多名为
DefineDynamicAssembly
的重载,通常是您开始的地方。这会返回一个AssemblyBuilder
,然后您可以使用诸如TypeBuilder
、PropertyBuilder
、MethodBuilder
等类型。 href="http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types.aspx" rel="noreferrer">CodeProject 文章 是关于使用反射发射创建动态类型的不错的入门读物。Take a look at the System.Reflection.Emit namespace. This will allow you to generate code at runtime. System.AppDomain has a number of overloads called
DefineDynamicAssembly
which is typically where you would start. This returns anAssemblyBuilder
and from there you use types likeTypeBuilder
,PropertyBuilder
,MethodBuilder
, etc. This CodeProject article is a decent primer on creating dynamic types with reflection emit.我一直致力于增强 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 的所有漂亮功能。
I've been working on enhancing an implementation of PSClass.
Implementation source:
https://github.com/ghostsquad/AetherClass/blob/master/functions/New-PSClass.ps1
Tests with usage:
https://github.com/ghostsquad/AetherClass/blob/master/test/New-PSClass.Tests.ps1
There's also functionality to mock psclasses, which is to say, you get all the nifty functionality of Moq with a dynamic psobject.