是否可以在没有项目设置的情况下在C#代码中#define定义一个常量解决方案? [英] Can I #define a constant solutionwide within c# code without project settings?

查看:142
本文介绍了是否可以在没有项目设置的情况下在C#代码中#define定义一个常量解决方案?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这很奇怪,并且回答了几次,例如 全解决方案的#define 如何在C#中全局定义常量(如DEBUG).

I know this was aksed and answered a a couple of times e.g. Solution-wide #define, Is There anyway to #define Constant on a Solution Basis? and How to define a constant globally in C# (like DEBUG).

但就我而言,我无法使用任何建议的方法:

But in my case I can not use any of the suggested methods:

我正在为UnityProjects(一种提供某种功能的程序包)编写不同的模块"(或插件,如果需要的话).这个想法是,开发人员可以通过导入其中包含所有脚本和资源的UnityPackage来加载某个模块"以在其项目中使用.

I'm writing on different "modules" (or plugins if you want so) for UnityProjects (kind of a package providing a certain functionality). The idea is that a developer can load a certain "module" to use in his project by importing a UnityPackage with all scripts and resources in it.

但是其中一些模块本身依赖于其他模块.所以到目前为止,我尝试的是在每个模块中都有一个Constants类,该类具有单独的名称空间和预处理器定义.

But some of these modules themselves depend on other modules. So what I tried so far was having a class Constants in each module with seperated namespaces and preprocessor definitions.

模块A

#if !MODULE_A
#define MODULE_A   // BUT I WOULD NEED THIS GLOBAL NOT ONLY HERE
#endif

    namespace Module_A
    {
        public static class Constants
        {
            // some constants for this namespace here
        }
    }

模块B

#if !MODULE_B
#define MODULE_B    // BUT I WOULD NEED THIS GLOBAL NOT ONLY HERE
#endif

#if !MODULE_A    // WILL BE NOT DEFINED OFCOURSE SINCE #define IS NOT GLOBAL
#error Module A missing!
#else

    namespace Module_B
    {
        public static class Constants
        {
            // some constants for this namespace here
        }

        // and other code that might require Module A
    }
#endif

但是,这当然不能像这样工作,因为#define不是全局的,而是仅在当前文件中.

But ofcourse this cannot work like this since #defines are not global but only in the current file.

对于模块的整个概念和简单的加载模块",我不能要求用户首先对项目或解决方案设置进行更改,例如由此答案建议,但必须仅使用UnityPackage随附的(c#)资源(至少与我的当前的专有技术).

For this whole idea of modules and a simple "load your modules" I can not ask the user to first make changes to the project or solution settings how e.g. suggested by this answer but instead have to use only the (c#) resources that come imported with the UnityPackage (at least with my current know-how).

有什么方法可以通过仅导入模块的UnityPackage为整个Unity-Project设置/定义这些常量吗?

我可以使用资产来在Unity中为 1 定义找到解决方案/msc.rsp .但这仍然不适用于多个模块,因为它们必须写入同一文件.

I could find a solution for 1 definition in Unity using Assets/msc.rsp. But this still wouldn't work for multiple modules since they would have to write into the same file.

推荐答案

经过大量搜索,我终于能够提出一个令人惊讶的简单解决方案,我想与您分享:

InitializeOnLoad

Unity具有属性 [InitializeOnLoad] .它告诉Unity尽快根据

Unity has an attribute [InitializeOnLoad]. It tells Unity to initialize according class as soon as

  • 团结开始
  • 重新编译脚本后=>以及使用脚本导入新的unitypackage之后

静态构造函数

在他们的在启动时运行编辑器代码的示例中,他们展示了如何组合使用static构造函数.

In their Running Editor Code On Launch example, they show, how to combine this with a static constructor.

来自静态-构造函数:

在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类.

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

通常您仍然需要创建该类的实例,但是在初始化该类时,静态构造函数会立即实例化/执行",这是我们使用[InitializeOnLoad]属性强制执行的.

While usually you still would have to create an instance of the class, the static constructor is "instanciated/executed" instantly when the class is initliazed, which we force using the [InitializeOnLoad] attribute.

脚本定义符号

进一步的Unity实际上PlayerSettings中已经在项目范围内定义.

Further Unity actually has project wide defines in the PlayerSettings.

好的是:我们还可以通过脚本API访问它们:

And the good part is: We also have access to them via scripting API:

所以我现在要做的是以下

So what I did now is the following

该模块没有依赖性,只是在PlayerSettings中定义了一个全局定义".我将此脚本放置在例如在Assets/ModuleA/Editor中(重要的是最后一个文件夹的名称).

This module has no dependencies but just defines a "global define" in the PlayerSettings. I placed this script somewhere e.g. in Assets/ModuleA/Editor (important is the last folder's name).

using System.Linq;
using UnityEditor;

namespace ModuleA
{
    // Will be initialized on load or recompiling
    [InitializeOnLoad]
    public static class Startup
    {
        // static constructor is called as soon as class is initialized
        static Startup()
        {
            #region Add Compiler Define

            // Get the current defines
            // returns a string like "DEFINE_1;DEFINE_2;DEFINE_3"
            var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
            // split into list just to check if my define is already there
            var define = defines.Split(';').ToList();

            if (!define.Contains("MODULE_A")
            {
                // if not there already add my define 
                defines += ";MODULE_A";
            }

            // and write back the new defines
            PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines);

            #endregion
        }
    }
}

模块B

此模块取决于Module A.因此,它本身定义了一个全局定义"(以便以后的模块可以检查它们在Module B上的依赖关系),但是另外,它还会首先检查是否导入了模块A.如果缺少Module A,它将向调试控制台输出错误.

Module B

This module depends on Module A. So itself defines a "global define" (so later Modules can check their dependecies on Module B) but additionally it checks first, if Module A is imported. If Module A is missing, it prints an error to the Debug Console.

(您也可以使用#error SOME TEXT引发编译器错误,但是由于某些原因,它无法正确打印出URL,因此我决定使用Debug.LogError)

(You could as well throw a compiler error using #error SOME TEXT, but for some reason this is not capable of printing out the URL correctly so I decided for the Debug.LogError)

我将此脚本放置在例如在Assets/ModuleB/Editor

I placed this script somewhere e.g. in Assets/ModuleB/Editor

#if MODULE_A
using System.Linq;
#endif
using UnityEditor;
#if !MODULE_A
using UnityEngine;
#endif

namespace ModuleB
{
    // Will be initialized on load or recompiling
    [InitializeOnLoad]
    public static class Startup
    {
        // static constructor is called as soon as class is initialized
        static Startup()
        {
#if !MODULE_A
            Debug.LogErrorFormat("! Missing Module Dependency !" +
                                 "\nThe module {0} depends on the module {1}." +
                                 "\n\nDownload it from {2} \n",
                "MODULE_B",
                "MODULE_A",
                "https://Some.page.where./to.find.it/MyModules/ModuleA.unitypackage"
                );
#else
            // Add Compiler Define

            var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
            var define = defines.Split(';').ToList();

            if (!define.Contains("MODULE_B"))
            {
                defines += ";MODULE_B";
            }

            PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, defines);

#endif
        }
    }
}


因此,稍后在 B模块的其他脚本中,我有两个选择(两者基本相同)


So later in other scripts of Module B I have two options (both do basically the same)

  • 我可以检查所有地方#if MODULE_A来准确检查此脚本所依赖的模块

  • I can either check everywhere #if MODULE_A to check exactly the module this script relies on

或我可以改为检查#if MODULE_B而不用一行来检查是否满足所有的依存关系,因为否则我将不定义MODULE_B.

or I can instead check #if MODULE_B to rather check with one line if all dependecies are fulfilled since otherwise I don't define MODULE_B.

通过这种方式,我可以完全检查某些模块之间的所有依赖关系,这是很棒的.到目前为止,我看到的仅有两个缺陷是:

On this way I can completely check all dependencies between certain modules which is awesome. The only two flaws I saw until now are:

  • 我们必须知道每个模块的定义(例如MODULE_A)是什么样子,如果将来更改,则还必须在所有依赖的模块中对其进行更改
  • 如果从项目中删除了模块,则不会删除全局定义"
  • We have to know how the define (e.g. MODULE_A) looks like for every module and if it is changed in the future it has to be changed in all depending modules as well
  • The "global define" isn't getting removed in case the module is deleted from the project

但是-哪种解决方案是完美的?

But well - which solution is perfect?

这篇关于是否可以在没有项目设置的情况下在C#代码中#define定义一个常量解决方案?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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