将从IL编译的程序集与.NET Core和Xamarin [英] Using assemblies compiled from IL with .NET Core & Xamarin

查看:85
本文介绍了将从IL编译的程序集与.NET Core和Xamarin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已更新了适用于我的解决方案。请参阅此问题的底部。

Updated with a solution that works for me. See the bottom of this question.

上下文:

我需要一种方法来评估泛型的大小为了计算数组长度以适合某个字节大小。基本上,
sizeof 类似于C / C ++提供的内容。

Context:
I needed a way to evaluate the size of a generic type for the purpose of calculating array lengths to fit within a certain byte size. Basically, sizeof similar to what C/C++ provides.

C#的 sizeof 元帅。 SizeOf 不适合此操作,因为它们有很多限制。

C#'s sizeof and Marshal.SizeOf are not suitable for this, because of their many limitations.

考虑到这一点,我在IL中编写了一个程序集,该程序集启用了我正在寻找的功能通过 sizeof 操作码。我知道它实质上是引用类型为 IntPtr.Size

With this in mind, I wrote an assembly in IL that enables the functionality I was looking for through the sizeof opcode. I'm aware that it essentially evaluates to IntPtr.Size with reference types.

我为.NET复制了此内容标准与核心,引用我认为是mscorlib的正确等效项。请注意,IL编译正常,此问题是另一个问题。

I duplicated this for .NET Standard & Core, referencing what I believed were the correct equivalents of mscorlib. Note that the IL compiles fine, this question is about another issue.

代码:

每个目标框架的标题:

Code:
Headers per target framework:

.NET:(Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe)

.NET: (Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe)

.assembly extern mscorlib {}

.NET标准:(从 nuget 提取的信息)

.NET Standard: (ilasm extracted from nuget)

.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 :(与标准情况相同,虽然我已经对两者进行了测试)

.NET Core: (same ilasm as standard, though I've tested with both)

.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应用程序引用,我收到以下错误:

Problem:
When any dll compiled in this manner is referenced by a .NET Core or Xamarin application, I receive the following error:


类型'Object'在程序集中定义未引用。
必须添加对程序集'System.Runtime,Version = 0.0.0.0,
Culture = neutral,PublicKeyToken = null'的引用。

The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

.dll项目或.NET标准库引用这些dll,然后再由.NET项目引用这些dll时,不会发生此问题。

This issue doesn't occur when such dlls are referenced by .NET projects or .NET standard libraries which are then referenced by a .NET project.

我阅读了无数文章,文章和存储库,详细介绍了使用不同版本和程序集的此错误。典型的解决方案似乎是为目标框架的mscorlib(破坏可移植性)添加一个明确的引用。似乎缺乏有关将IL编译的程序集用于.NET Standard& amp;的信息。

I've read countless articles, posts, and repositories detailing this error with different versions and assemblies. The typical solution seems to be to add an explicit reference to the target framework's equivalent of mscorlib(breaking portability). There seems to be a lack of information about using IL compiled assemblies for .NET Standard & Core.

据我了解,.NET Standard&核心使用外观来转发类型定义,以便它们可以由目标框架的运行时解析,从而实现可移植性。

To my understanding, .NET Standard & Core use facades that forward type definitions so they may be resolved by the target framework's runtime, enabling portability.

我尝试了以下操作:


  • System.Runtime
  • 的明确版本
  • 反汇编.NET Core库使用完全相同的引用从C#编译。奇怪的是,它们似乎针对显式版本(例如.NET Core 2.0中的System.Runtime 4.2)。

  • 使用 Emit API 。编译到内存似乎可以工作,但不是可行的选择,因为我也将目标锁定为Xamarin.iOS(仅适用于AOT)。从磁盘引用这种动态编译的程序集会导致与我手动编译它们相同的错误。

  • Explicit versions of System.Runtime
  • Disassembling .NET Core libraries compiled from C#, using the exact same references. Oddly enough they seem to target explicit versions(such as System.Runtime 4.2 in .NET Core 2.0).
  • Generating the code dynamically using the Emit API. Compiling to memory appears to work, but isn't an option because I'm also targeting Xamarin.iOS(AOT only). Referencing such dynamically compiled assemblies from disk results in the same error as if I compiled them manually.

更新:

我在 Jacek的答案中尝试了该解决方案(按照构建说明此处),但是无法将我的系统配置为使用构建脚本或VS2017。但是,在挖掘 System.Runtime.CompilerServices.Unsafe 我发现了一个解决方案。

Update:
I attempted the solution in Jacek's answer(following the build instructions here), yet couldn't configure my system to compile corefx with the build script or VS 2017. However, after digging through the code of System.Runtime.CompilerServices.Unsafe I discovered a solution.

这似乎很明显,但是我指的是 System.Runtime 的错误版本。

This probably seems obvious, but I was referencing the wrong version of System.Runtime.

每个目标框架的标题(从corefx复制):

Headers per target framework(copied from 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 :

.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 )。

In all source files, use CORELIB to reference types in mscorlib(i.e. [CORELIB]System.Object).

推荐答案

在DotNet CoreFX存储库中有一个很好的示例,说明了如何正确执行此操作。 System.Runtime.CompilerServices。不安全 是仅IL的程序集,可以由.NET Core和Xamarin使用。

There is a very good example of how to do it correctly in the DotNet CoreFX repo. System.Runtime.CompilerServices.Unsafe is an IL only assembly and can be used by .NET Core and Xamarin.

https://github.com/dotnet/corefx/tree/master/src/System .Runtime.CompilerServices.Unsafe

有两种方法可以解决此问题:(i)尝试从头开始在项目中重新创建构建配置的必需元素-将会非常耗时并且非常复杂-corefx构建系统非常复杂,(ii)使用现有的构建基础结构,并通过复制 System.Runtime.CompilerServices.Unsafe在.NET Core CoreFX存储库中创建您的IL项目。 项目,更改命名并将IL代码替换为您的代码。在我看来,这是构建基于IL的程序集的最快方法,可以保证可以与所有目标正常工作。

There are two approaches to the problem: (i) try to recreate required elements of the build configuration in your project from scratch - what will be time consuming and very involved - corefx build system is really complex, (ii) use existing build infrastructure and create your IL project inside .NET Core CoreFX repo by replicating System.Runtime.CompilerServices.Unsafe project, changing naming and and replacing IL code with yours. In my opinion this is the fastest way to build IL based assembly which will be guaranteed to work properly with all targets.

在针对任何特定版本的时构建程序集。 NET Core或.NET Standard只需在发布分支中创建它: release / 2.0.0 release / 1.1.0 等。

To build your assembly while targeting any particular version of .NET Core or .NET Standard just create it in the release branches: release/2.0.0, release/1.1.0 etc.


类型'Object'是在未引用的程序集中定义的。您必须添加对程序集'System.Runtime,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'的引用。

The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

有一个选项可以尝试仅在触发该错误的项目引用程序集中抑制该编译错误。将以下属性设置为新格式​​csproj / vbproj应该可以抑制它:

There is an option to try for suppressing that compilation error alone in a project referencing assembly that triggers it. Putting the following property to a new format csproj/vbproj should suppress it:

<PropertyGroup>
    <_HasReferenceToSystemRuntime>true</_HasReferenceToSystemRuntime>
</PropertyGroup>

这篇关于将从IL编译的程序集与.NET Core和Xamarin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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