我更新了一种对我有用的解决方案,请参见问题底部。
背景:
我需要一种评估通用类型大小以计算数组长度以适应特定字节大小的方法。基本上,类似于C/C++提供的sizeof
。
C#的sizeof
和Marshal.SizeOf不适合此目的,因为它们有许多限制。
有了这个想法,我编写了一个在IL中启用所需功能的程序集,该程序集通过sizeof
操作码实现。我知道它基本上对引用类型求值为IntPtr.Size
。
我在.NET Standard和Core上复制了这个程序集,并引用了我认为是mscorlib的正确等价项。请注意,IL编译得很好,这个问题与另一个问题有关。
代码:
每个目标框架的头文件:
.NET:(Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe)
.assembly extern mscorlib {}
.NET标准:(从nuget提取的ilasm)
.assembly extern netstandard
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89)
.ver 0:0:0:0
}
.assembly extern System.Runtime
{
.ver 0:0:0:0
}
.NET Core:(与标准版相同的ilasm,尽管我已经测试过两种版本)
.assembly extern System.Runtime
{
.ver 0:0:0:0
}
来源:
.assembly Company.IL
{
.ver 0:0:1:0
}
.module Company.IL.dll
// CORE is a define for mscorlib, netstandard, and System.Runtime
.class public abstract sealed auto ansi beforefieldinit
Company.IL.Embedded extends [CORE]System.Object
{
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
ldarg.0
call instance void [CORE]System.Object::.ctor()
ret
}
.method public hidebysig static uint32
SizeOf<T>() cil managed
{
sizeof !!0
ret
}
}
问题:当任何以这种方式编译的dll被.NET Core或Xamarin应用程序引用时,我会收到以下错误信息:
类型“Object”在未被引用的程序集中定义。您必须添加对程序集“System.Runtime,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null”的引用。
当此类dll被.NET项目或.NET标准库引用,然后再由.NET项目引用时,不会出现此问题。
我已经阅读了无数关于此错误的文章、帖子和代码库,它们涉及不同版本和程序集。通常的解决方案似乎是向目标框架的等效mscorlib显式添加引用(破坏可移植性)。似乎缺乏有关使用IL编译的程序集进行.NET Standard和Core的信息。
据我所知,.NET Standard和Core使用外观(facades)转发类型定义,以便可以通过目标框架的运行时解析它们,从而实现可移植性。
我尝试了以下操作:
System.Runtime
的显式版本- 反编译由C#编译的.NET Core库,使用完全相同的引用。奇怪的是它们似乎针对显式版本(例如.NET Core 2.0中的System.Runtime 4.2)。
- 使用Emit API动态生成代码。编译到内存似乎可以工作,但不是一个选项,因为我也在针对Xamarin.iOS(仅限AOT)。从磁盘引用这样动态编译的程序集会导致与手动编译它们一样的错误。
更新:
我尝试了Jacek的答案中的解决方案(根据这里的构建说明),但无法配置我的系统以使用构建脚本或VS 2017编译corefx。然而,在查看System.Runtime.CompilerServices.Unsafe的代码后,我发现了一个解决方案。
这可能显而易见,但是我引用了错误版本的System.Runtime
。
每个目标框架的头文件(从corefx复制):
.NET:
#define CORELIB "mscorlib"
.assembly extern CORELIB {}
.NET标准:
#define CORELIB "System.Runtime"
#define netcoreapp
// Metadata version: v4.0.30319
.assembly extern CORELIB
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 4:0:0:0
}
.NET Core:
#define CORELIB "System.Runtime"
// Metadata version: v4.0.30319
.assembly extern CORELIB
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 4:0:0:0
}
在所有源文件中,使用
CORELIB
来引用mscorlib中的类型(例如,[CORELIB]System.Object
)。
Reflection.Emit
尝试的结果是什么? - thehennyy