更新了适用于我的解决方案。请参阅此问题的底部。
上下文
我需要一种方法来评估泛型类型的大小,以便计算适合某个字节大小的数组长度。基本上,
sizeof
类似于C / C ++提供的内容。
C#' sizeof
和Marshal.SizeOf不适用于此,因为它们有很多限制。
考虑到这一点,我在IL中编写了一个程序集,通过sizeof
操作码启用了我正在寻找的功能。我知道它基本上使用引用类型评估为IntPtr.Size
。
我为.NET Standard& amp;核心,引用我认为是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核心:(与标准相同,虽然我已经对两者进行了测试)
.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应用程序引用时,我收到以下错误:
类型&#39;对象&#39;在未引用的程序集中定义。 您必须添加对程序集&System; Run.Runtime,Version = 0.0.0.0的引用, Culture = neutral,PublicKeyToken = null&#39;。
当.NET项目或.NET标准库引用这些dll然后由.NET项目引用时,不会发生此问题。
我已经阅读了无数文章,帖子和存储库,详细说明了使用不同版本和程序集的错误。典型的解决方案似乎是添加对目标框架的明确引用,相当于mscorlib(破解可移植性)。似乎缺乏有关将.NET编译程序集用于.NET Standard&amp;芯
根据我的理解,.NET Standard&amp;转换类型定义的核心使用外观,以便它们可以由目标框架的运行时解析,从而实现可移植性。
我尝试过以下方法:
System.Runtime
更新
我尝试了Jacek's answer中的解决方案(遵循构建说明here),但是无法配置我的系统以使用构建脚本或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
)。
答案 0 :(得分:3)
有一个很好的例子说明如何在DotNet CoreFX repo中正确地完成它。 System.Runtime.CompilerServices.Unsafe
是一个仅限IL的程序集,可供.NET Core和Xamarin使用。
https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe
有两种方法可以解决这个问题:(i)尝试从头开始重新创建项目中构建配置的必需元素 - 这将耗费大量时间并且非常复杂 - corefx构建系统非常复杂,(ii)使用现有的通过复制System.Runtime.CompilerServices.Unsafe
项目,更改命名以及用您的代码替换IL代码,构建基础架构并在.NET Core CoreFX仓库中创建IL项目。在我看来,这是构建基于IL的装配的最快方法,可以保证与所有目标一起正常工作。
要针对任何特定版本的.NET Core或.NET Standard构建程序集,只需在发布分支中创建它:release/2.0.0
,release/1.1.0
等。
“Object”类型在未引用的程序集中定义。您必须添加对程序集'System.Runtime,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'的引用。
有一个选项可以尝试在引发触发它的程序集中单独抑制编译错误。将以下属性设置为新格式csproj / vbproj应该禁止它:
<PropertyGroup>
<_HasReferenceToSystemRuntime>true</_HasReferenceToSystemRuntime>
</PropertyGroup>
答案 1 :(得分:0)
好的,这是我研究的结果(基于https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe和https://github.com/jvbsl/ILProj):
global.json
:
{
"msbuild-sdks": {
"Microsoft.NET.Sdk.IL": "3.0.0-preview-27318-01"
}
}
ILProj\ILProj.ilproj
:
<Project Sdk="Microsoft.NET.Sdk.IL">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<MicrosoftNetCoreIlasmPackageVersion>3.0.0-preview-27318-01</MicrosoftNetCoreIlasmPackageVersion>
<IncludePath Condition="'$(TargetFramework)' == 'netstandard1.0'">include\netstandard</IncludePath>
<IncludePath Condition="'$(TargetFramework)' == 'netstandard2.0'">include\netstandard</IncludePath>
<IncludePath Condition="'$(TargetFramework)' == 'netcoreapp1.0'">include\netcoreapp</IncludePath>
<IncludePath Condition="'$(TargetFramework)' == 'netcoreapp2.0'">include\netcoreapp</IncludePath>
<IlasmFlags>$(IlasmFlags) -INCLUDE=$(IncludePath)</IlasmFlags>
</PropertyGroup>
</Project>
ILProj\include\netstandard\coreassembly.h
:
#define CORE_ASSEMBLY "System.Runtime"
// Metadata version: v4.0.30319
.assembly extern CORE_ASSEMBLY
{
.publickeytoken = ( B0 3F 5F 7F 11 D5 0A 3A )
.ver 4:0:0:0
}
ILProj\Class.il
#include "coreassembly.h"
.assembly ILProj
{
.ver 1:0:0:0
}
.module ILProj.dll
.class public abstract auto ansi sealed beforefieldinit ILProj.Class
extends [CORE_ASSEMBLY]System.Object
{
.method public hidebysig static int32 Square(int32 a) cil managed
{
.maxstack 2
ldarg.0
dup
mul
ret
}
}
如果您很难将所有内容放在一起,请在此处查看示例:https://github.com/Konard/ILProj