英文:
The type or namespace name 'Newtonsoft' could not be found (PS 5.1)
问题
我正尝试使用Newtonsoft.Json库:
[Reflection.Assembly]::LoadFile('C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json.0.2.201\libs\Newtonsoft.Json.dll')
Add-Type -TypeDefinition @"
using Newtonsoft.Json;
class BigIntegerConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Org.BouncyCastle.Math.BigInteger));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
System.Numerics.BigInteger big = (System.Numerics.BigInteger)reader.Value;
return new Org.BouncyCastle.Math.BigInteger(big.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value.ToString());
}
}
"@
并且出现以下错误:
无法找到类型或命名空间名称'Newtonsoft'(您是否缺少使用指令或程序集引用?)
为什么它无法找到Newtonsoft,即使已加载?我可以在PowerShell代码中通过[Newtonsoft.Json.JsonConverter]调用它,但在类型定义中无法使用它!
谢谢!
英文:
I'm trying to use Newtonsoft.Json library:
[Reflection.Assembly]::LoadFile( 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json.0.2.201\libs\Newtonsoft.Json.dll' )
Add-Type -TypeDefinition @"
using Newtonsoft.Json;
class BigIntegerConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Org.BouncyCastle.Math.BigInteger));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
System.Numerics.BigInteger big = (System.Numerics.BigInteger)reader.Value;
return new Org.BouncyCastle.Math.BigInteger(big.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value.ToString());
}
}
"@
and getting the next error:
> The type or namespace name 'Newtonsoft' could not be found (are you missing a using directive or an assembly reference?)
Why it can't find Newtonsoft tho it loaded? I can call it in PS code via [Newtonsoft.Json.JsonConverter], but not in type definitions!
Thanks!
答案1
得分: 2
<!-- language-all: sh -->
假设在调用脚本之前加载了`Newtonsoft.Json.dll`和`BouncyCastle.Cryptography.dll`程序集 - 例如,使用`Add-Type -LiteralPath 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json.0.2.201\libs\Newtonsoft.Json.dll'` - **您可以使用PowerShell代码定义您的类**,即一个**PowerShell [`class`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Classes)定义**,如下所示:
注意:假设已在运行此脚本之前加载了Newtonsoft.Json.dll和BouncyCastle.Cryptography.dll。
class BigIntegerConverter : Newtonsoft.Json.JsonConverter {
[bool] CanConvert([Type] $objectType){
return $objectType -is [Org.BouncyCastle.Math.BigInteger]
}
[object] ReadJson([Newtonsoft.Json.JsonReader] $reader, [Type] $objectType, [object] $existingValue, [Newtonsoft.Json.JsonSerializer] $serializer) {
[bigint] $big = $reader.Value
return [Org.BouncyCastle.Math.BigInteger]::new($big.ToString())
}
WriteJson([Newtonsoft.Json.JsonWriter] $writer, [object] $value, [Newtonsoft.Json.JsonSerializer] $serializer) {
$writer.WriteRawValue($value.ToString())
}
}
对于在PowerShell中的类定义中必须在手头的脚本之前加载任何类型的要求,可参考此答案中的讨论[这里](https://stackoverflow.com/a/51813639/45375)。
---
至于**您尝试的内容**:
Mathias正确地指出,**通常情况下,您只需要确保将传递给[`Add-Type`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Add-Type)的C#代码编译所需的程序集传递给`-ReferencedAssemblies`**。
由于我不清楚的原因,特别是针对`Newtonsoft.Json.dll`,以下代码还需要**在此之前**加载`Newtonsoft.Json.dll`程序集。
* 注意:以下**代码仅适用于Windows PowerShell** - 与上面的PowerShell `class`实现不同,后者在两个版本中均有效。
* 但是,**可以在PowerShell(Core)7+**中使其工作,需要额外的工作:
* 使用`NewtonSoft.Json.dll`的*.NET Standard 2.0*实现(所有实现都包含在同一个[`Newtonsoft.Json`](https://www.nuget.org/packages/Newtonsoft.Json) NuGet包中)
* 在`-ReferencedAssemblies`参数中:
* 添加`netstandard`
* 将`System.Numerics`替换为`System.Runtime.Numerics`
* 然后不需要使用`Add-Type -LiteralPath`预先加载`Newtonsoft.Json.dll`。
* 或者,使用程序集的*.NET(Core)*实现:
* 执行与上述相同的步骤,除了添加`netstandard`
* 将`-IgnoreWarnings -WarningAction Ignore`添加到`Add-Type`调用中,以忽略和消除关于PowerShell的.NET运行时版本与`Newtonsoft.Json.dll`目标版本之间不匹配的警告。
* 如果*意外*使用了*.NET Framework*实现,您将收到有关找不到核心类型(例如`Object`)的错误,可能是因为它们在.NET Framework程序集中查找。
$jsonAssembly = 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json\1.0.2.201\libs\Newtonsoft.Json.dll'
在此处指定BouncyCastle.Cryptography.dll的路径。
$bouncyCastleAssembly = 'C:\path\to\BouncyCastle.Cryptography.dll'
!! 不可解释地,这也是必需的,可能也适用于BouncyCastle.Cryptography.dll
Add-Type -LiteralPath $jsonAssembly
Add-Type -ReferencedAssemblies $jsonAssembly, $bouncyCastleAssembly, System.Numerics -TypeDefinition @'
using System;
using System.Numerics;
using Newtonsoft.Json;
public class BigIntegerConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Org.BouncyCastle.Math.BigInteger));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
BigInteger big = (BigInteger)reader.Value;
return new Org.BouncyCastle.Math.BigInteger(big.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value.ToString());
}
'@
还请注意:
* 添加`using System;`以启用无命名空间引用`Type`类
* 在`-ReferencedAssemblies`中添加`System.Numerics`以及在代码中添加`using System.Numerics;`以允许无命名空间引用`BigInteger`
* 在`BigInterConverter`类定义中添加`public`以确保生成的类是公共的。
英文:
<!-- language-all: sh -->
Assuming you load the Newtonsoft.Json.dll
and BouncyCastle.Cryptography.dll
assemblies before invoking your script - e.g., with Add-Type -LiteralPath 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json\1.0.2.201\libs\Newtonsoft.Json.dll'
- you can define your class using PowerShell code, i.e. a PowerShell class
definition, as follows:
# Note: Assumes that Newtonsoft.Json.dll and BouncyCastle.Cryptography.dll
# were loaded *before* running this script.
class BigIntegerConverter : Newtonsoft.Json.JsonConverter {
[bool] CanConvert([Type] $objectType){
return $objectType -is [Org.BouncyCastle.Math.BigInteger]
}
[object] ReadJson([Newtonsoft.Json.JsonReader] $reader, [Type] $objectType, [object] $existingValue, [Newtonsoft.Json.JsonSerializer] $serializer) {
[bigint] $big = $reader.Value
return [Org.BouncyCastle.Math.BigInteger]::new($big.ToString())
}
WriteJson([Newtonsoft.Json.JsonWriter] $writer, [object] $value, [Newtonsoft.Json.JsonSerializer] $serializer) {
$writer.WriteRawValue($value.ToString())
}
}
The - unfortunate - requirement that any types referenced in a PowerShell class
have to have been loaded before the script at hand is parsed is discussed in this answer.
As for what you tried:
Mathias is correct in that you normally only need to make sure that the assemblies needed for compiling the C# code passed to Add-Type
be passed to -ReferencedAssemblies
.
For reasons unknown to me, with Newtonsoft.Json.dll
specifically, the code below additionally requires loading the Newtonsoft.Json.dll
assembly beforehand too.
- Note: The code below works in Windows PowerShell only - unlike the PowerShell
class
implementation above, which works in both editions.- However, it can be made to work in PowerShell (Core) 7+, with extra effort:
-
Use the .NET Standard 2.0 implementation of
NewtonSoft.Json.dll
(all implementations are part of the sameNewtonsoft.Json
NuGet package)- In the
-ReferencedAssemblies
argument:- Add
netstandard
- Replace
System.Numerics
withSystem.Runtime.Numerics
- Add
- You then do not load
Newtonsoft.Json.dll
beforehand withAdd-Type -LiteralPath
.
- In the
-
Alternatively, use the .NET (Core) implementation of the assembly:
- Follow the same steps as above, except for adding
netstandard
- Add
-IgnoreWarnings -WarningAction Ignore
to theAdd-Type
call, to ignore and silence warnings regarding a version mismatch between PowerShell's .NET runtime version and the one targeted byNewtonsoft.Json.dll
- Follow the same steps as above, except for adding
-
If you accidentally use a .NET Framework implementation, you'll get errors about not finding core types such as
Object
, presumably because they're looked for in .NET Framework assemblies.
-
- However, it can be made to work in PowerShell (Core) 7+, with extra effort:
$jsonAssembly = 'C:\Users\user\Documents\WindowsPowerShell\Modules\newtonsoft.json.0.2.201\libs\Newtonsoft.Json.dll'
# Specify the path to BouncyCastle.Cryptography.dll here.
$bouncyCastleAssembly = 'C:\path\to\BouncyCastle.Cryptography.dll'
# !! Inexplicably, this is needed too, possibly also for BouncyCastle.Cryptography.dll
Add-Type -LiteralPath $jsonAssembly
Add-Type -ReferencedAssemblies $jsonAssembly, $bouncyCastleAssembly, System.Numerics -TypeDefinition @'
using System;
using System.Numerics;
using Newtonsoft.Json;
public class BigIntegerConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Org.BouncyCastle.Math.BigInteger));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
BigInteger big = (BigInteger)reader.Value;
return new Org.BouncyCastle.Math.BigInteger(big.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(value.ToString());
}
'@
Also note:
-
The addition of
using System;
to enable namespace-free references to classType
-
The addition of
System.Numerics
to-ReferencedAssemblies
as well asusing System.Numerics;
to allow namespace-free references toBigInteger
-
Adding
public
to theBigInterConverter
class definition to ensure that the resulting class is public.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论