[GameFramework分析] Log(日志)

2023-10-26

使用

// 调试日志
Log.Debug("Hello, world!");
// 信息日志
Log.Info("Hello, world!");
// 警告日志
Log.Warning("Hello, world!");
// 错误日志
Log.Error("Hello, world!");
// 严重错误日志
Log.Fatal("Hello, world!");

分析

Unity脚本

Log

Unity脚本调用该类来打印日志。

(内部就是转发了框架中的 GameFrameworkLog类

代码

using GameFramework;
using System.Diagnostics;

namespace UnityGameFramework.Runtime
{
    /// <summary>
    /// 日志工具集。
    /// </summary>
    public static class Log
    {
        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项且带有 ENABLE_LOG、ENABLE_DEBUG_LOG 或 ENABLE_DEBUG_AND_ABOVE_LOG 预编译选项时生效。</remarks>
        [Conditional("ENABLE_LOG")]
        [Conditional("ENABLE_DEBUG_LOG")]
        [Conditional("ENABLE_DEBUG_AND_ABOVE_LOG")]
        public static void Debug(object message)
        {
            GameFrameworkLog.Debug(message);
        }
        
        // 省略代码...
    }
}

注意点

  • 静态类(工具类)
  • 使用 预处理指令(宏)Conditional特性 设置是否忽略方法调用
  • 预处理指令使用 LogScriptingDefineSymbols类ScriptingDefineSymbols类 进行设置

ConditionalAttribute(Conditional特性)

指示编译器,除非定义了指定的有条件编译符号,否则,应忽略方法调用或属性。

参考文档

ConditionalAttribute 类

保留的特性:ConditionalAttribute, ObsoleteAttribute, AttributeUsageAttribute

LogScriptingDefineSymbols

设置Log相关的预处理指令

在Unity编辑器中生成菜单项(让使用者快速设置日志等级)

代码

using UnityEditor;

namespace UnityGameFramework.Editor
{
    /// <summary>
    /// 日志脚本宏定义。
    /// </summary>
    public static class LogScriptingDefineSymbols
    {
        private const string EnableLogScriptingDefineSymbol = "ENABLE_LOG";
        private const string EnableDebugAndAboveLogScriptingDefineSymbol = "ENABLE_DEBUG_AND_ABOVE_LOG";
        private const string EnableInfoAndAboveLogScriptingDefineSymbol = "ENABLE_INFO_AND_ABOVE_LOG";
        private const string EnableWarningAndAboveLogScriptingDefineSymbol = "ENABLE_WARNING_AND_ABOVE_LOG";
        private const string EnableErrorAndAboveLogScriptingDefineSymbol = "ENABLE_ERROR_AND_ABOVE_LOG";
        private const string EnableFatalAndAboveLogScriptingDefineSymbol = "ENABLE_FATAL_AND_ABOVE_LOG";
        private const string EnableDebugLogScriptingDefineSymbol = "ENABLE_DEBUG_LOG";
        private const string EnableInfoLogScriptingDefineSymbol = "ENABLE_INFO_LOG";
        private const string EnableWarningLogScriptingDefineSymbol = "ENABLE_WARNING_LOG";
        private const string EnableErrorLogScriptingDefineSymbol = "ENABLE_ERROR_LOG";
        private const string EnableFatalLogScriptingDefineSymbol = "ENABLE_FATAL_LOG";

        private static readonly string[] AboveLogScriptingDefineSymbols = new string[]
        {
            EnableDebugAndAboveLogScriptingDefineSymbol,
            EnableInfoAndAboveLogScriptingDefineSymbol,
            EnableWarningAndAboveLogScriptingDefineSymbol,
            EnableErrorAndAboveLogScriptingDefineSymbol,
            EnableFatalAndAboveLogScriptingDefineSymbol
        };

        private static readonly string[] SpecifyLogScriptingDefineSymbols = new string[]
        {
            EnableDebugLogScriptingDefineSymbol,
            EnableInfoLogScriptingDefineSymbol,
            EnableWarningLogScriptingDefineSymbol,
            EnableErrorLogScriptingDefineSymbol,
            EnableFatalLogScriptingDefineSymbol
        };

        /// <summary>
        /// 禁用所有日志脚本宏定义。
        /// </summary>
        [MenuItem("Game Framework/Log Scripting Define Symbols/Disable All Logs", false, 30)]
        public static void DisableAllLogs()
        {
            ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableLogScriptingDefineSymbol);

            foreach (string specifyLogScriptingDefineSymbol in SpecifyLogScriptingDefineSymbols)
            {
                ScriptingDefineSymbols.RemoveScriptingDefineSymbol(specifyLogScriptingDefineSymbol);
            }

            foreach (string aboveLogScriptingDefineSymbol in AboveLogScriptingDefineSymbols)
            {
                ScriptingDefineSymbols.RemoveScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
            }
        }

        /// <summary>
        /// 开启所有日志脚本宏定义。
        /// </summary>
        [MenuItem("Game Framework/Log Scripting Define Symbols/Enable All Logs", false, 31)]
        public static void EnableAllLogs()
        {
            DisableAllLogs();
            ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
        }

        /// <summary>
        /// 开启调试及以上级别的日志脚本宏定义。
        /// </summary>
        [MenuItem("Game Framework/Log Scripting Define Symbols/Enable Debug And Above Logs", false, 32)]
        public static void EnableDebugAndAboveLogs()
        {
            SetAboveLogScriptingDefineSymbol(EnableDebugAndAboveLogScriptingDefineSymbol);
        }
        
        // 省略代码...

        /// <summary>
        /// 设置日志脚本宏定义。
        /// </summary>
        /// <param name="aboveLogScriptingDefineSymbol">要设置的日志脚本宏定义。</param>
        public static void SetAboveLogScriptingDefineSymbol(string aboveLogScriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(aboveLogScriptingDefineSymbol))
            {
                return;
            }

            foreach (string i in AboveLogScriptingDefineSymbols)
            {
                if (i == aboveLogScriptingDefineSymbol)
                {
                    DisableAllLogs();
                    ScriptingDefineSymbols.AddScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
                    return;
                }
            }
        }
    }
}

注意点

  • 静态类(工具类)
  • 使用 MenuItem特性 在Unity编辑器中生成菜单项
  • 使用 ScriptingDefineSymbols类 设置 预处理指令

ScriptingDefineSymbols

设置 预处理指令 的工具类

代码

using System.Collections.Generic;
using UnityEditor;

namespace UnityGameFramework.Editor
{
    /// <summary>
    /// 脚本宏定义。
    /// </summary>
    public static class ScriptingDefineSymbols
    {
        private static readonly BuildTargetGroup[] BuildTargetGroups = new BuildTargetGroup[]
        {
            BuildTargetGroup.Standalone,
            BuildTargetGroup.iOS,
            BuildTargetGroup.Android,
            BuildTargetGroup.WSA,
            BuildTargetGroup.WebGL
        };

        /// <summary>
        /// 检查指定平台是否存在指定的脚本宏定义。
        /// </summary>
        /// <param name="buildTargetGroup">要检查脚本宏定义的平台。</param>
        /// <param name="scriptingDefineSymbol">要检查的脚本宏定义。</param>
        /// <returns>指定平台是否存在指定的脚本宏定义。</returns>
        public static bool HasScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(scriptingDefineSymbol))
            {
                return false;
            }

            string[] scriptingDefineSymbols = GetScriptingDefineSymbols(buildTargetGroup);
            foreach (string i in scriptingDefineSymbols)
            {
                if (i == scriptingDefineSymbol)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 为指定平台增加指定的脚本宏定义。
        /// </summary>
        /// <param name="buildTargetGroup">要增加脚本宏定义的平台。</param>
        /// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
        public static void AddScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(scriptingDefineSymbol))
            {
                return;
            }

            if (HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
            {
                return;
            }

            List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup))
            {
                scriptingDefineSymbol
            };

            SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
        }

        /// <summary>
        /// 为指定平台移除指定的脚本宏定义。
        /// </summary>
        /// <param name="buildTargetGroup">要移除脚本宏定义的平台。</param>
        /// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
        public static void RemoveScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(scriptingDefineSymbol))
            {
                return;
            }

            if (!HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
            {
                return;
            }

            List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup));
            while (scriptingDefineSymbols.Contains(scriptingDefineSymbol))
            {
                scriptingDefineSymbols.Remove(scriptingDefineSymbol);
            }

            SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
        }

        /// <summary>
        /// 为所有平台增加指定的脚本宏定义。
        /// </summary>
        /// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
        public static void AddScriptingDefineSymbol(string scriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(scriptingDefineSymbol))
            {
                return;
            }

            foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
            {
                AddScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
            }
        }

        /// <summary>
        /// 为所有平台移除指定的脚本宏定义。
        /// </summary>
        /// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
        public static void RemoveScriptingDefineSymbol(string scriptingDefineSymbol)
        {
            if (string.IsNullOrEmpty(scriptingDefineSymbol))
            {
                return;
            }

            foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
            {
                RemoveScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
            }
        }

        /// <summary>
        /// 获取指定平台的脚本宏定义。
        /// </summary>
        /// <param name="buildTargetGroup">要获取脚本宏定义的平台。</param>
        /// <returns>平台的脚本宏定义。</returns>
        public static string[] GetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup)
        {
            return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';');
        }

        /// <summary>
        /// 设置指定平台的脚本宏定义。
        /// </summary>
        /// <param name="buildTargetGroup">要设置脚本宏定义的平台。</param>
        /// <param name="scriptingDefineSymbols">要设置的脚本宏定义。</param>
        public static void SetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup, string[] scriptingDefineSymbols)
        {
            PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", scriptingDefineSymbols));
        }
    }
}

注意点

  • 静态类(工具类)
  • 使用 Unity的PlayerSettings类 设置 预处理指令

PlayerSettings

Player Settings 是您为即将在 Unity 中构建的最终游戏定义各种参数的地方。

其中一些值将用于您打开独立平台游戏时所启动的分辨率对话框。

参考文档

PlayerSettings

Unity中的预处理指令设置

Scripting Define Symbols

DefaultLogHelper

默认的日志辅助器类

代码

using GameFramework;
using UnityEngine;

namespace UnityGameFramework.Runtime
{
    /// <summary>
    /// 默认游戏框架日志辅助器。
    /// </summary>
    public class DefaultLogHelper : GameFrameworkLog.ILogHelper
    {
        /// <summary>
        /// 记录日志。
        /// </summary>
        /// <param name="level">日志等级。</param>
        /// <param name="message">日志内容。</param>
        public void Log(GameFrameworkLogLevel level, object message)
        {
            switch (level)
            {
                case GameFrameworkLogLevel.Debug:
                    Debug.Log(Utility.Text.Format("<color=#888888>{0}</color>", message.ToString()));
                    break;

                case GameFrameworkLogLevel.Info:
                    Debug.Log(message.ToString());
                    break;

                case GameFrameworkLogLevel.Warning:
                    Debug.LogWarning(message.ToString());
                    break;

                case GameFrameworkLogLevel.Error:
                    Debug.LogError(message.ToString());
                    break;

                default:
                    throw new GameFrameworkException(message.ToString());
            }
        }
    }
}

框架类

GameFrameworkLogLevel

框架的日志等级

代码

namespace GameFramework
{
    /// <summary>
    /// 游戏框架日志等级。
    /// </summary>
    public enum GameFrameworkLogLevel : byte
    {
        /// <summary>
        /// 调试。
        /// </summary>
        Debug = 0,

        /// <summary>
        /// 信息。
        /// </summary>
        Info,

        /// <summary>
        /// 警告。
        /// </summary>
        Warning,

        /// <summary>
        /// 错误。
        /// </summary>
        Error,

        /// <summary>
        /// 严重错误。
        /// </summary>
        Fatal
    }
}

GameFrameworkLog.ILogHelper

日志辅助器接口

namespace GameFramework
{
    public static partial class GameFrameworkLog
    {
        /// <summary>
        /// 游戏框架日志辅助器接口。
        /// </summary>
        public interface ILogHelper
        {
            /// <summary>
            /// 记录日志。
            /// </summary>
            /// <param name="level">游戏框架日志等级。</param>
            /// <param name="message">日志内容。</param>
            void Log(GameFrameworkLogLevel level, object message);
        }
    }
}

注意点

  • 该接口处于静态分部类 GameFrameworkLog 的里面

分部类

拆分一个类、一个结构、一个接口或一个方法的定义到两个或更多的文件中是可能的。

每个源文件包含类型或方法定义的一部分,编译应用程序时将把所有部分组合起来。

参考文档

分部类和方法(C# 编程指南)

自定义日志辅助器流程

  1. 创建一个类并继承该接口(如:MyLogHelper)
  2. 切换到 Unity编辑器 ,打开 游戏启动场景
  3. 在从场景下的 BaseComponent(Game Framework/Builtin) 的检视面板中选择 日志辅助器类

GameFrameworkLog

游戏框架日志类

代码

using System.Diagnostics;

namespace GameFramework
{
    /// <summary>
    /// 游戏框架日志类。
    /// </summary>
    public static partial class GameFrameworkLog
    {
        private static ILogHelper s_LogHelper = null;

        /// <summary>
        /// 设置游戏框架日志辅助器。
        /// </summary>
        /// <param name="logHelper">要设置的游戏框架日志辅助器。</param>
        public static void SetLogHelper(ILogHelper logHelper)
        {
            s_LogHelper = logHelper;
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(object message)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, message);
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="message">日志内容。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(string message)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, message);
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(string format, object arg0)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg0));
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        /// <param name="arg1">日志参数 1。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(string format, object arg0, object arg1)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg0, arg1));
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        /// <param name="arg1">日志参数 1。</param>
        /// <param name="arg2">日志参数 2。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(string format, object arg0, object arg1, object arg2)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, arg0, arg1, arg2));
        }

        /// <summary>
        /// 打印调试级别日志,用于记录调试类日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="args">日志参数。</param>
        /// <remarks>仅在带有 DEBUG 预编译选项时生效。</remarks>
        [Conditional("DEBUG")]
        public static void Debug(string format, params object[] args)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Debug, Utility.Text.Format(format, args));
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="message">日志内容</param>
        public static void Info(object message)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, message);
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="message">日志内容</param>
        public static void Info(string message)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, message);
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        public static void Info(string format, object arg0)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg0));
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        /// <param name="arg1">日志参数 1。</param>
        public static void Info(string format, object arg0, object arg1)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg0, arg1));
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="arg0">日志参数 0。</param>
        /// <param name="arg1">日志参数 1。</param>
        /// <param name="arg2">日志参数 2。</param>
        public static void Info(string format, object arg0, object arg1, object arg2)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, arg0, arg1, arg2));
        }

        /// <summary>
        /// 打印信息级别日志,用于记录程序正常运行日志信息。
        /// </summary>
        /// <param name="format">日志格式。</param>
        /// <param name="args">日志参数。</param>
        public static void Info(string format, params object[] args)
        {
            if (s_LogHelper == null)
            {
                return;
            }

            s_LogHelper.Log(GameFrameworkLogLevel.Info, Utility.Text.Format(format, args));
        }

        // 省略代码...
    }
}

注意点

  • 静态分部类
  • 使用 ILogHelper接口 记录日志
  • 在游戏启动时,BaseComponent组件(Unity脚本) 会调用 SetLogHelper方法 设置日志辅助器。
  • 应该是 策略模式

类图

Log

Log

GameFrameworkLog

GameFrameworkLog

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[GameFramework分析] Log(日志) 的相关文章

随机推荐

  • Mysql使用USE INDEX()优化查询

    语法 SELECT FROM TABLE USE IGNORE FORCE INDEX key list WHERE USE INDEX 用来提供你希望Mysql去参考的索引列表 就可以让Mysql不再考虑使用其他可用的索引 IGNORE
  • CGAL的使用

    1 C 类的知识 因为CGAL是用C 实现的 所以需要先了解一下C 编程 C 是面向对象的编程 这也是C 对C语言改进的最重要的部分 C 也被叫做是 带类的 C 简单讲一下类的构成 成员函数以及对象的定义和使用 1 1 C 类的构成 首先从
  • PAT C入门题目-7-124 天梯赛座位分配 (20 分)(动态内存分配)

    7 124 天梯赛座位分配 20 分 天梯赛每年有大量参赛队员 要保证同一所学校的所有队员都不能相邻 分配座位就成为一件比较麻烦的事情 为此我们制定如下策略 假设某赛场有 N 所学校参赛 第 i 所学校有 M i 支队伍 每队 10 位参赛
  • 【自学Linux】 Linux文件目录结构

    Linux文件目录结构 Linux文件目录结构教程 在 Linux 中 有一个很经典的说法 叫做一切皆文件 因此 我们在系统学习 Linux 之前 首先要了解 Linux 的文件目录结构 Linux 主要的目录有三大类 即根目录 usr 目
  • Tracy vue3 小笔记 1 - 如何使用 VUE, MVC, MVVM, Template, Vue 源码

    Vue Demo code 计数器那么安装和使用Vue这个JavaScript库有哪些方式呢 方式一 在页面中通过CDN的方式来引入 方式二 下载Vue的JavaScript文件 并且自己手动引入 方式三 通过npm包管理工具安装使用它 w
  • 智能输液系统(STM32+ESP8266-01S+阿里云+安卓APP)

    下位机 阿里云 APP 下位机流转上位机
  • 2021-08-19-leetcode-00001

    二分查找 704 给定一个 n 个元素有序的 升序 整型数组 nums 和一个目标值 target 写一个函数搜索 nums 中的 target 如果目标值存在返回下标 否则返回 1 278 你是产品经理 目前正在带领一个团队开发新的产品
  • Linux 学习笔记3 权限管理 定时任务 网络配置 进程、软件包管理

    权限管理 linux组的介绍 在linux中的每个用户必须属于一个组 不能独立于组外 在linux中每个文件有所有者 所在组 其它组的概念 1 所有者 2 所在组 3 其它组 4 改变用户所在的组 文件 目录所有者 一般为文件的创建者谁创建
  • kettle进阶之database join

    前言 这并不是一篇入门教学 且不是一篇高阶教学 仅仅针对kettle的database join 那么问题来了 kettle的database join是什么 简而言之 不同库之间sql语句传值 个人自定义 如有不当 请海涵 案例1 一条数
  • SQL Server 集合处理

    UNION ALL 返回两个结果集中所有的行 返回结果集中会存在重复行 UNION 返回两个结果集中去重的行 返回结果集中无重复行 INTERSECT 返回两个结果集都有的行 返回结果集中无重复行 EXCEPT 返回第一个结果集中有而第二个
  • vuex与生命周期的关系

    vue与生命周期的关系 问题呈现 获取到数据同时保存到vuex中 2 计算属性获取vuex中的值 3 循环输出 4 出现错误 问题解析 如果单独输出item questionSimpleInfo是可以输出整个对象的 但是输出其中某一个字段的
  • 论文阅读-Thinking in Frequency: Face Forgery Detection by Mining Frequency-aware Clues(F3Net基于频率感知线索的人脸)

    一 论文信息 题目 Thinking in Frequency Face Forgery Detection by Mining Frequency aware Clues 基于频率感知线索的人脸伪造检测 作者团队 会议 ECCV 2020
  • Markdown矩阵及公式语法编辑

    Markdown矩阵及公式语法编辑 详见链接 https cloud tencent com developer article 1402840
  • 9. xaml ComboBox控件

    1 运行图像 2 运行源码 a Xaml源码
  • C++中虚函数、虚指针和虚表详解

    关于虚函数的背景知识 用virtual关键字申明的函数叫做虚函数 虚函数肯定是类的成员函数 存在虚函数的类都有一个一维的虚函数表叫做虚表 每一个类的对象都有一个指向虚表开始的虚指针 虚表是和类对应的 虚表指针是和对象对应的 多态性是一个接口
  • Windows CMD 输出文本到文件,不加换行符

    gt test txt set p Hello
  • 共筑安全创新生态,持安科技加入麒麟软件安全生态联盟

    近日 麒麟软件安全生态联盟第二季度工作会议成功举行 零信任办公安全领域明星企业持安科技受邀参会 并参与授牌环节成为麒麟软件安全生态联盟会员单位 麒麟软件安全生态联盟授牌仪式 会上 联盟成员单位围绕操作系统安全事件与漏洞发展趋势 行业应用对操
  • Beego v2.0 编译后无法运行问题

    问题 beego版本 v2 0 1 通过bee pack be GOOS linux 打包后运行可执行程序报错 如下 panic err go command required not found exec go executable fi
  • Vue+Element-ui Table 列求和

    Vue Element ui Table 列求和 Vue代码 求和getSummaries 效果图 Vue代码
  • [GameFramework分析] Log(日志)

    文章目录 使用 分析 Unity脚本 Log LogScriptingDefineSymbols ScriptingDefineSymbols DefaultLogHelper 框架类 GameFrameworkLogLevel GameF