d5884
d5884

Reputation: 906

How to access Add-Type defined type in other Add-Type type definition?

How to access a type defined by Add-Type -TypeDefinition "..." in another Add-Type -TypeDefinition "..."?

In the following code example, in spite of the same namespace, a compiler cannot find the UserCode type.

Add-Type -TypeDefinition @"
namespace SampleCode {
    public struct UserCode {
         public string Name;
         public string Id;
    }
}
"@

#.... do something ....

Add-Type -TypeDefinition @"
namespace SampleCode {
    public struct UserInformation {
        public UserCode User;
        public string Note;
    }
}
"@
# => Error ... Add-Type : <temporary source path>(3) : The type or namespace name
# 'UserCode' could not be found (are you missing a using directive or an assembly
# reference?)

Upvotes: 11

Views: 10267

Answers (2)

user189198
user189198

Reputation:

In order to reference the first .NET assembly from the second .NET assembly, you need to persist the first .NET assembly to disk. Once you've done this, you can reference the first .NET assembly from the second .NET assembly using the -ReferencedAssemblies parameter of the Add-Type cmdlet.

IMPORTANT: If you use two different namespaces in your two different C# code blocks, make sure that you declare your using statements appropriately in the second code block.

Here is an example, showing you how to:

  1. Dynamically compile a new .NET assembly to disk
  2. Import a dynamic assembly that references another assembly on-disk

Part 1 - Assembly #1

The first .NET Assembly must be output to disk so that we can reference it. Therefore, we will use the -OutputAssembly and -OutputType parameters of the Add-Type cmdlet to create it.

$Csharp = @"
using System;
using System.Reflection;

namespace Widget {
    public class UserCode {
        public static int GetValue() {
            return 2;
        }
    }
}
"@

# Define the output path for the new .NET Assembly
$OutputAssembly = '{0}\Widget.dll' -f $env:USERPROFILE;

# Compile the code and output a new .NET assembly
Add-Type -TypeDefinition $Csharp -OutputAssembly $OutputAssembly -OutputType Library;

# Load the .NET Assembly 
[System.Reflection.Assembly]::LoadFile($OutputAssembly);

Part 2 - Assembly #2

We don't have to worry about compiling the second .NET assembly to disk, because we are not referencing it from any other assemblies. Therefore, we can simply use the Add-Type cmdlet to compile it into a temporary, in-memory assembly. We must make sure that we use the -ReferencedAssemblies parameter to reference the .NET Assembly that we compiled in Part 1.

# Now that we have a compiled .NET Assembly, we need to write our new code
# that references it (make sure to include all appropriate C# "using" statements)

# Define the second set of C# code
$CsharpCode2 = @"
using Widget;

namespace NASA {
    public class Shuttle {
        public int Boosters;
        public Shuttle() {
            this.Boosters = UserCode.GetValue();
        }
    }
}
"@;

# Try to compile the new code, but wait, we get an error ...
# ... because this code is dependent on the code contained in the
# Widget assembly
$Assembly2 = Add-Type -TypeDefinition $CsharpCode2 -PassThru;

# We have to reference the .NET Assembly that defines the UserCode type
$Assembly2 = Add-Type -TypeDefinition $CsharpCode2 -ReferencedAssemblies $OutputAssembly -PassThru;

# Now we can successfully create the NASA.Shuttle object;
$Shuttle = New-Object -TypeName NASA.Shuttle;

# View the number of boosters the Shuttle instance has
Write-Host -Object $Shuttle.Boosters;

Upvotes: 14

Jason Shirk
Jason Shirk

Reputation: 8019

This isn't possible with dynamic assemblies (which are generated by default if you don't specify other parameters.)

You can generate dlls with Add-Type and reference them later, so something like:

Add-Type -OutputAssembly foo1.dll ...
Add-Type -ReferencedAssemblies foo1.dll ...

should work.

Upvotes: 1

Related Questions