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

发布于 2024-10-24 03:11:07 字数 2252 浏览 1 评论 0原文

我有一些从数据源获取的数据,这些数据是我存储在 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 提供的工具执行此操作的清晰示例。似乎应该有一种方法可以通过扩展 PSObjectPSPropertyPSMethod 类在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁对谁错谁最难过 2024-10-31 03:11:07

定义自己的新类的能力是他们在 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

The ability to define your own new classes is something new they added in PowerShell v2. Here is a sample:

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

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:

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

PS H:\> $splat

Name    Value
----    -----
Name    Goyuix
Site    stackoverflow.com
Tag     powershell
懒猫 2024-10-31 03:11:07

查看 System.Reflection.Emit 命名空间 。这将允许您在运行时生成代码。 System.AppDomain 有许多名为 DefineDynamicAssembly 的重载,通常是您开始的地方。这会返回一个 AssemblyBuilder,然后您可以使用诸如 TypeBuilderPropertyBuilderMethodBuilder 等类型。 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 an AssemblyBuilder and from there you use types like TypeBuilder, PropertyBuilder, MethodBuilder, etc. This CodeProject article is a decent primer on creating dynamic types with reflection emit.

一瞬间的火花 2024-10-31 03:11:07

我一直致力于增强 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文