Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically define a class in C# PowerShell Cmdlet

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?

like image 699
DSO Avatar asked Mar 18 '11 17:03

DSO


People also ask

How do you define a class in C?

C ClassesA class consists of an instance type and a class object: An instance type is a struct containing variable members called instance variables and function members called instance methods. A variable of the instance type is called an instance.

Can we create a class at runtime?

Dynamic Class creation enables you to create a Java class on the fly at runtime, from source code created from a string. Dynamic class creation can be used in extremely low latency applications to improve performance.

Can we create a class dynamically in C#?

You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.


2 Answers

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
like image 130
Goyuix Avatar answered Nov 14 '22 20:11

Goyuix


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.

like image 25
Keith Hill Avatar answered Nov 14 '22 21:11

Keith Hill