Skip to content

Instantly share code, notes, and snippets.

@proxb
Created April 27, 2017 22:54
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save proxb/2ba54e570045b13c4cf10df0e708f2d7 to your computer and use it in GitHub Desktop.
Save proxb/2ba54e570045b13c4cf10df0e708f2d7 to your computer and use it in GitHub Desktop.
Using PowerShell and Reflection to dynamically build a Struct with Constructors and Methods
#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName(([guid]::NewGuid().ToString()))
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule(([guid]::NewGuid().ToString()), $False)
#endregion Module Builder
#region STRUCTs
#Order of creating these Structs is important
#region MyStruct
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$STRUCT_TypeBuilder = $ModuleBuilder.DefineType('Person', $Attributes, [System.ValueType], 8)
$FirstName_Field = $STRUCT_TypeBuilder.DefineField('FirstName', [string], 'Public')
$LastName_Field = $STRUCT_TypeBuilder.DefineField('LastName', [string], 'Public')
$Age_Field = $STRUCT_TypeBuilder.DefineField('Age', [int], 'Public')
#region Constructors
#Default Constructor
$ObjType = [Type]::GetType('System.Object')
$ctor = $ObjType.GetConstructor([type]::EmptyTypes)
$ConstructorBuilder = $STRUCT_TypeBuilder.DefineConstructor('Public', [System.Reflection.CallingConventions]::Standard, @())
$ILGen = $ConstructorBuilder.GetILGenerator()
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg,0)
$ILGen.Emit([Reflection.Emit.OpCodes]::Call, $ctor)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ret)
#First, Last and Age Constructor
$ObjType = [Type]::GetType('System.Object')
$ctor = $ObjType.GetConstructor([type]::EmptyTypes)
$ConstructorBuilder = $STRUCT_TypeBuilder.DefineConstructor('Public', [System.Reflection.CallingConventions]::Standard, @([string], [string], [int]))
$ILGen = $ConstructorBuilder.GetILGenerator()
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg,0)
$ILGen.Emit([Reflection.Emit.OpCodes]::Call, $ctor)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 0)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 1)
$ILGen.Emit([Reflection.Emit.OpCodes]::Stfld, $FirstName_Field)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 0)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 2)
$ILGen.Emit([Reflection.Emit.OpCodes]::Stfld, $LastName_Field)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 0)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ldarg, 3)
$ILGen.Emit([Reflection.Emit.OpCodes]::Stfld, $Age_Field)
$ILGen.Emit([Reflection.Emit.OpCodes]::Ret)
#endregion Constructors
#region Methods
#FirstName
$Method = $STRUCT_TypeBuilder.DefineMethod('_GetFirstName','Private', ([int]), $Null)
$MethodIL = $Method.GetILGenerator()
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ldfld, $FirstName_Field)
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ret)
#LastName
$Method = $STRUCT_TypeBuilder.DefineMethod('_GetLastName','Private', ([int]), $Null)
$MethodIL = $Method.GetILGenerator()
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ldfld, $LastName_Field)
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ret)
#Age
$Method = $STRUCT_TypeBuilder.DefineMethod('_GetAge','Private', ([int]), $Null)
$MethodIL = $Method.GetILGenerator()
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ldfld, $Age_Field)
$MethodIL.Emit([Reflection.Emit.OpCodes]::Ret)
#endregion Methods
[void]$STRUCT_TypeBuilder.CreateType()
#endregion MyStruct
#Test it out
[Person]::New('Boe','Prox',36)
<#
FirstName LastName Age
--------- -------- ---
Boe Prox 36
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment