如何获取PowerShell的添加类型以使用添加的类型 [英] How can I get PowerShell Added-Types to use Added Types

查看:119
本文介绍了如何获取PowerShell的添加类型以使用添加的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究一个PoSh项目,该项目生成CSharp代码,然后 Add-Type 将其存储到内存中。

I'm working on a PoSh project that generates CSharp code, and then Add-Types it into memory.

新类型使用磁盘DLL中的现有类型,该DLL通过Add-Type加载。

The new types use existing types in an on disk DLL, which is loaded via Add-Type.

一切都很好,直到我实际上尝试在新类型上调用方法。以下是我正在执行的操作的示例:

All is well and good untill I actualy try to invoke methods on the new types. Here's an example of what I'm doing:

$PWD = "."
rm -Force $PWD\TestClassOne*
$code = "
namespace TEST{
public class TestClassOne
{
    public int DoNothing()
    {
        return 1;
    }
}
}"
$code | Out-File tcone.cs
Add-Type -OutputAssembly $PWD\TestClassOne.dll -OutputType Library -Path $PWD\tcone.cs
Add-Type -Path $PWD\TestClassOne.dll
$a = New-Object TEST.TestClassOne
"Using TestClassOne"
$a.DoNothing()


"Compiling TestClassTwo"
Add-Type -Language CSharpVersion3 -TypeDefinition "
namespace TEST{
public class TestClassTwo
{
    public int CallTestClassOne()
    {
        var a = new TEST.TestClassOne();
        return a.DoNothing();
    }
}
}" -ReferencedAssemblies $PWD\TestClassOne.dll
"OK"
$b = New-Object TEST.TestClassTwo
"Using TestClassTwo"
$b.CallTestClassOne()

运行上面的脚本在最后一行给出以下错误:

Running the above script gives the following error on the last line:

使用 0参数调用 CallTestClassOne的异常):
无法加载文件或程序集'TestClassOne,...'
或其依赖项之一。系统找不到指定的文件。
在AddTypeTest.ps1:39 char:20
+ $ b.CallTestClassOne<<<< ()
+ CategoryInfo:未指定:(:) [],MethodInvocationException
+ FullyQualifiedErrorId:DotNetMethodException

Exception calling "CallTestClassOne" with "0" argument(s): "Could not load file or assembly 'TestClassOne,...' or one of its dependencies. The system cannot find the file specified." At AddTypeTest.ps1:39 char:20 + $b.CallTestClassOne <<<< () + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException

我在做什么错了?

推荐答案

之所以发生这种情况,是因为CLR加载程序在应用程序(PowerShell)的基本目录中查找任何程序集。当然,它在那里找不到您的程序集。解决此问题的最佳方法是挂接stej提到的AssemblyResolve事件,但使用该事件告诉CLR程序集在哪里。您无法使用PowerShell 2.0的Register-ObjectEvent来执行此操作,因为它不适用于需要返回值的事件(即程序集)。在这种情况下,让我们通过添加类型使用更多的C#为我们完成这项工作。此代码段有效:

This happens because any assemblies are looked for by the CLR loader in the application's (PowerShell's) base directory. Of course, it doesn't find your assembly there. The best way to solve this is to hook the AssemblyResolve event as stej mentions but use it to tell the CLR where the assembly is. You can't do this with PowerShell 2.0's Register-ObjectEvent because it doesn't work with events that require a return value (ie the assembly). In this case, let's use more C# via Add-Type to do this work for us. This snippet of code works:

ri .\TestClassOne.dll -for -ea 0

$resolver = @'
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Utils
{
    public static class AssemblyResolver
    {
        private static Dictionary<string, string> _assemblies;

        static AssemblyResolver()
        {
            var comparer = StringComparer.CurrentCultureIgnoreCase;
            _assemblies = new Dictionary<string,string>(comparer);
            AppDomain.CurrentDomain.AssemblyResolve += ResolveHandler;
        }

        public static void AddAssemblyLocation(string path)
        {
            // This should be made threadsafe for production use
            string name = Path.GetFileNameWithoutExtension(path);
            _assemblies.Add(name, path);
        }

        private static Assembly ResolveHandler(object sender, 
                                               ResolveEventArgs args) 
        {
            var assemblyName = new AssemblyName(args.Name);
            if (_assemblies.ContainsKey(assemblyName.Name))
            {
                return Assembly.LoadFrom(_assemblies[assemblyName.Name]);
            }
            return null;
        }
    }
}
'@

Add-Type -TypeDefinition $resolver -Language CSharpVersion3

$code = @'
namespace TEST {
    public class TestClassOne {
        public int DoNothing() {
            return 1;
        }
    }
}
'@
$code | Out-File tcone.cs
Add-Type -OutputAssembly TestClassOne.dll -OutputType Library -Path tcone.cs

# This is the key, register this assembly's location with our resolver utility
[Utils.AssemblyResolver]::AddAssemblyLocation("$pwd\TestClassOne.dll")

Add-Type -Language CSharpVersion3 `
         -ReferencedAssemblies "$pwd\TestClassOne.dll" `
         -TypeDefinition @'
namespace TEST {
    public class TestClassTwo {
        public int CallTestClassOne() {
            var a = new TEST.TestClassOne();
            return a.DoNothing();
        }
    }
}
'@ 

$b = new-object Test.TestClassTwo
$b.CallTestClassOne()

这篇关于如何获取PowerShell的添加类型以使用添加的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆