# 托管插件

> Details on using managed plug-ins.

托管插件是在 Unity 外部使用 Visual Studio 等工具创建并编译到动态链接库 (DLL) 中的 [.NET 程序集](/engine/6000.0/manual/scripting/environment-and-tools/overview-of-dot-net-in-unity/dotnet-profile-support.md)。

此过程与标准 C# 脚本不同，Unity 将这些脚本作为源文件存储在 Unity 项目的 Assets 文件夹中。Unity 会在标准 C# 脚本发生更改时编译这些脚本，而 DLL 是预编译的，其不会发生更改。可以将编译的 .dll 文件添加到项目中，并以与标准脚本相同的方式将其包含的类附加到**游戏对象**。

有关 C# 中的托管代码的更多信息，请参阅 Microsoft 的[什么是托管代码？](https://docs.microsoft.com/en-us/dotnet/standard/managed-code)文档。

托管插件仅包含 .NET 代码，因此无法访问 .NET 库不支持的任何功能。但是，Unity 使用的标准 .NET 工具可以访问托管代码来编译脚本。

在 Unity 中使用 DLL 时，必须完成比使用脚本时更多的步骤。但是，在某些情况下，创建 .dll 文件并将其添加到 Unity 项目可能会很有帮助，例如：

* 希望在代码中使用 Unity 不支持的编译器。
* 希望在 .dll 文件中添加第三方 .NET 代码。
* 希望向 Unity 提供没有源代码的代码。

本页面介绍了可用于创建托管插件的一般方法，以及如何使用 Visual Studio 创建托管插件和设置调试会话。

## 创建托管插件##creating-a-managed-plug-in

要创建托管插件，需要先创建 DLL。为此，您需要合适的编译器，例如：

* [Visual Studio](https://visualstudio.microsoft.com/)
* [MsBuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild?view=vs-2019)
* [.NET SDK](https://docs.microsoft.com/en-us/dotnet/core/sdk)

并非所有能生成 .NET 代码的编译器都能与 Unity 兼容，因此在使用编译器进行重要工作之前，应使用一些可用的代码来测试该编译器是否兼容。用于创建 DLL 的方法取决于 DLL 是否包含 Unity API 代码：

* 如果 DLL 包含 Unity API 代码，则需要在编译之前向编译器提供 Unity 自己的 DLL：

  1. 要查找 Unity DLL，请执行以下操作：

     * 在 Windows 上，前往：`C:\Program Files\Unity\Hub\Editor\<version-number>\Editor\Data\Managed\UnityEngine`

     * macOS：

       1. 在计算机上查找 `Unity.app` 文件。在 macOS 上，Unity DLL 的路径为：`/Applications/Unity/Hub/Editor/<version-number>/Unity.app/Contents/Managed/UnityEngine`
       2. 右键单击 `Unity.app`
       3. 选择**显示包内容 (Show Package Contents)**。

  2. `UnityEngine` 文件夹包含了许多模块的 .dll 文件。引用它们可以将其用于脚本。某些命名空间还需要引用 Unity 项目中的编译库（例如，`UnityEngine.UI`）。在项目文件夹的目录中找到：`~\Library\ScriptAssemblies`

* 如果 DLL 不包含 Unity API 代码，或者您已使 Unity DLL 可用，则请按照编译器的文档编译 .dll 文件。用于编译 DLL 的确切选项取决于所使用的编译器。例如，Roslyn 编译器 `csc` 的命令行在 macOS 上可能如下所示：

`csc /r:/Applications/Unity/Hub/Editor/<version-number>/Unity.app/Contents/Managed/UnityEngine.dll /target:library /out:MyManagedAssembly.dll /recurse:*.cs`

在此示例中：

* 使用 `/r` 选项指定要包含在构建中的库的路径，在本例中为 `UnityEngine` 库。
* 使用 `/target` 选项指定所需的构建类型；“library”表示 DLL 构建。
* 使用 `/out` 指定库的名称，在本例中为“MyManagedAssembly.dll”。
* 添加要包含的源文件的名称。使用 `/recurse` 方法可以将所有以“.cs”结尾的文件添加到当前工作目录和所有子文件夹中。生成的 .dll 文件出现在与源文件相同的文件夹中。

## 使用托管插件##using-a-managed-plug-in

完成 DLL 编译后，便可以像任何其他资源一样将 .dll 文件拖到 Unity 项目中。然后可以：

* 展开托管插件以查看库中的单独类。
* 将派生自 MonoBehaviour 的类拖到游戏对象上。
* 直接从其他脚本中使用非 MonoBehaviour 类。


**类可见的展开 DLL:**
![](/api/media?file=/engine/6000.0/media/images/managed-plugin.png)

## 使用 Visual Studio 创建 DLL##create-a-dll-with-visual-studio

本节介绍了：

* 如何构建一个简单的 DLL 示例并将其与 Visual Studio 集成
* 如何在 Unity 中为 DLL 准备调试会话。

### 设置项目##setting-up-the-project

1. 打开 Visual Studio 并创建一个新项目。

2. 选择**文件 (File)** > **新建 (New)** > **项目 (Project)** > **Visual C#** > **.Net Standard** > **类库 (Class Library) (.NET Standard)**。

3. 将以下信息添加至新库：

   * **名称 (Name)**：命名空间（在此示例中使用 `DLLTest` 作为名称）。
   * **位置 (Location)**：项目的父文件夹。
   * **解决方案名称 (Solution name)**：项目的文件夹。

4. 使 Unity DLL 可用于脚本。在 Visual Studio 中，打开解决方案资源管理器 (Solution Explorer) 中的**引用 (References)** 上下文菜单，然后选择**添加引用 (Add Reference)** > **浏览 (Browse)** > **选择文件 (Select File)**。

5. 选择位于 UnityEngine 文件夹中的所需 .dll 文件。

### DLL 编码##coding-the-dll

1. 对于此示例，请在解决方案 (Solution) 浏览器中将默认类重命名为 `MyUtilities`。
2. 将其代码替换为以下内容：

```
using System;   
using UnityEngine;

namespace DLLTest {

    public class MyUtilities {
    
        public int c;

        public void AddValues(int a, int b) {
            c = a + b;  
        }
    
        public static int GenerateRandom(int min, int max) {
            System.Random rand = new System.Random();
            return rand.Next(min, max);
        }
    }
}
```

3. 构建项目以便生成 DLL 文件及其调试符号。

## 在 Unity 中调试 DLL##debugging-a-dll-in-unity

要在 Unity 中为 DLL 设置调试会话，请执行以下操作：

1. 在 Unity 中创建一个新项目，并将构建的 .dll 文件（例如 `<project folder>/bin/Debug/DLLTest.dll`）复制到 Assets 文件夹中。
2. 在 Assets 文件夹中创建一个名为 Test 的 C# 脚本。
3. 将其内容替换为脚本，该脚本可创建在 DLL 中创建的类的新实例，使用其函数并在**控制台 (Console)** 窗口中显示输出。例如，要从以上部分为 DLL 创建测试脚本，请复制以下代码：

```
using UnityEngine;
using System.Collections;
using DLLTest;

public class Test : MonoBehaviour {

     void Start () {
        MyUtilities utils = new MyUtilities();
        utils.AddValues(2, 3);
        print("2 + 3 = " + utils.c);
     }
    
     void Update () {
        print(MyUtilities.GenerateRandom(0, 100));
     }
}
```

4. 将此脚本附加到场景中的游戏对象，然后单击播放 (Play)。

Unity 在控制台窗口中显示 DLL 中的代码输出

## 编译不安全 C# 代码##compiling-unsafe-c-code

[不安全 C# 代码](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unsafe)是指能够直接访问内存的代码。它在默认情况下不会启用，因为编译器无法验证它是否会引入安全风险。

在执行以下操作时可能需要用到不安全代码：

* 使用指针访问内存。
* 分配原始内存。
* 使用指针调用方法。

要启用编译不安全 C# 代码，请选择**编辑 (Edit)** > **项目设置 (Project Settings)** > **播放器 (Player)** > **其他设置 (Other Settings)** 并启用**允许不安全代码 (Allow Unsafe Code)**。

有关更多信息，请参阅 [Microsoft 的不安全代码文档](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code)。

## 其他资源##additional-resources

* [原生插件](/engine/6000.0/manual/scripting/compilation-and-code-reload/plug-ins/native.md)
* [桌面端插件](/engine/6000.0/manual/scripting/compilation-and-code-reload/plug-ins/for-desktop.md)
* [原生插件接口](/engine/6000.0/manual/scripting/compilation-and-code-reload/plug-ins/native-plugin-interface.md)
