• .NET Core 获取程序运行环境信息与反射的应用


    笔者的九篇反射系统文章已经完结,但是笔者会持续更新反射在日常撸码中的应用。
    本篇内容主要是 .NET Core 获取运行环境信息、利用反射更加方便地处理数据。
    本篇内容有:RuntimeInformation、Environment、反射、特性等。
    本篇代码下载地址 https://gitee.com/whuanle/reflection_and_properties/blob/master/反射特性应用场景1.cs

    获取示例:

    笔者的九篇反射系列文章阅读地址如下:
    C# 反射与特性(一):反射基础

    C# 反射与特性(二):探究反射

    C# 反射与特性(三):反射类型的成员

    C# 反射与特性(四):实例化类型

    C# 反射与特性(五):类型成员操作

    C# 反射与特性(六):实现 ASP.NET Core 依赖注入 Web

    C# 反射与特性(七):自定义特性以及应用

    C# 反射与特性(八):反射操作实例大全

    C# 反射与特性(九):解析反射实例大全

    RuntimeInformation、Environment


    RuntimeInformation 类提供有关 .NET 运行时安装的信息。主要获取平台以及 版本,API较少。
    文档地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.runtimeinformation?view=netcore-3.1
    Environment 提供有关当前环境和平台的信息以及操作它们的方法。API比较多。
    文档地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.environment?view=netcore-3.1

    以上两个类已经提供了文档地址,这里不再赘述。
    需要注意的是,Windows、Linux 之间有差异,因此有些 API 是无法跨平台的。另外 .NET Core 相对 .NET Framework ,对获取系统资源信息等的 API 十分少。
    .NET Core 是无有 API 获取系统 CPU 情况和 内存使用情况,倒是可以获取当前进程的 CPU 和 内存使用情况。
    可以查看 stackoverflow 了解。
    https://stackoverflow.com/questions/54215334/how-to-measure-cpu-usage-and-memory-for-a-process-in-net-core-linux

    获取信息


    下面获取的属于进程使用的内存已经使用 CPU 时间。
    CPU 时间不像直接获取到的 使用百分比,可以很直观地看到。
    CPU 时间地公式如下。
    CPU时间 = 执行程序所需的时钟周期数 * 时钟周期时间
    CPU 有多核多线程,因此不能按照运行多长时间去计算。同时进程存在休眠、上下文切换等情况。
    程序运行了几小时,有可能CPU时间只有几十分钟。
    对 CPU 性能计算方法有兴趣,请参考 https://www.cnblogs.com/whuanle/p/12260224.html
    对 Linux CPU 使用率计算有兴趣,请查看 https://www.cnblogs.com/aresxin/p/9152127.html

    我们在 C# 中使用地代码如下

        [Display(Name = "运行信息")]
        public class ApplicationRunInfo
        {
            private double _UsedMem;
            private double _UsedCPUTime;
            public ApplicationRunInfo()
            {
                var proc = Process.GetCurrentProcess();
                var mem = proc.WorkingSet64;
                var cpu = proc.TotalProcessorTime;
                _UsedMem = mem / 1024.0;
                _UsedCPUTime = cpu.TotalMilliseconds;
            }
            [Display(Name = "进程已使用物理内存(kb)")]
            public double UsedMem { get { return _UsedMem; } }
            [Display(Name = "进程已占耗CPU时间(ms)")]
            public double UsedCPUTime { get { return _UsedCPUTime; } }
        }
    

    这里只有两个属性。
    我们使用 Display 特性来标记此属性地的含义,方便反射时获取信息。

    另外还有两个获取不同类型信息的类如下

    
        [Display(Name = "系统运行平台")]
        public class SystemPlatformInfo
        {
            [Display(Name = "运行框架")]
            public string FrameworkDescription { get { return RuntimeInformation.FrameworkDescription; } }
            [Display(Name = "操作系统")]
            public string OSDescription { get { return RuntimeInformation.OSDescription; } }
            [Display(Name = "操作系统版本")]
            public string OSVersion { get { return Environment.OSVersion.ToString(); } }
            [Display(Name = "平台架构")]
            public string OSArchitecture { get { return RuntimeInformation.OSArchitecture.ToString(); } }
        }
    
        [Display(Name = "运行环境")]
        public class SystemRunEvnInfo
        {
            [Display(Name = "机器名称")]
            public string MachineName { get { return Environment.MachineName; } }
            [Display(Name = "用户网络域名")]
            public string UserDomainName { get { return Environment.UserDomainName; } }
            [Display(Name = "分区磁盘")]
            public string GetLogicalDrives { get { return string.Join(", ", Environment.GetLogicalDrives()); } }
            [Display(Name = "系统目录")]
            public string SystemDirectory { get { return Environment.SystemDirectory; } }
            [Display(Name = "系统已运行时间(毫秒)")]
            public int TickCount { get { return Environment.TickCount; } }
    
            [Display(Name = "是否在交互模式中运行")]
            public bool UserInteractive { get { return Environment.UserInteractive; } }
            [Display(Name = "当前关联用户名")]
            public string UserName { get { return Environment.UserName; } }
            [Display(Name = "Web程序核心框架版本")]
            public string Version { get { return Environment.Version.ToString(); } }
    
            //对Linux无效
            [Display(Name = "磁盘分区")]
            public string SystemDrive { get { return Environment.ExpandEnvironmentVariables("%SystemDrive%"); } }
            //对Linux无效
            [Display(Name = "系统目录")]
            public string SystemRoot { get { return Environment.ExpandEnvironmentVariables("%SystemRoot%"); } }
        }
    

    可能你会觉得,为什么不写成方法,为啥要写得这么奇怪。不急,慢慢看下去~

    反射获取信息

    我们来定义一个静态类型,作为获取各种信息的入口。

    public static class EnvironmentInfo
    {
    
    }
    }
    

    获取属性值

    反射获取属性值的方法,用于获取上述几个类的属性值。

            /// <summary>
            /// 获取属性的值
            /// </summary>
            /// <param name="info"></param>
            /// <param name="obj">实例</param>
            /// <returns></returns>
            private static object GetPropertyInfoValue(PropertyInfo info, object obj)
            {
                return info.GetValue(obj);
            }
    

    反射获取特性值

    我们使用了特性 [Display(Name = "当前关联用户名")] 来存储别名。
    我们要通过反射获取 Dispaly 特性的 Name 属性值。

            /// <summary>
            /// 获取 [Display] 特性的属性 Name 的值
            /// </summary>
            /// <param name="attrs"></param>
            /// <returns></returns>
            private static string GetDisplayNameValue(IList<CustomAttributeData> attrs)
            {
                var argument = attrs.FirstOrDefault(x => x.AttributeType.Name == nameof(DisplayAttribute)).NamedArguments;
                return argument.FirstOrDefault(x => x.MemberName == nameof(DisplayAttribute.Name)).TypedValue.Value.ToString();
            }
    

    获取某个属性的值以及别名


    我们使用了这样的方式去设置获取一项信息

            [Display(Name = "操作系统")]
            public string OSDescription { get { return RuntimeInformation.OSDescription; } }
    

    因此我们要获取到一个类型所有的属性值和属性的特性值。

            /// <summary>
            /// 获取某个类型的值以及名称
            /// </summary>
            /// <typeparam name="TInfo"></typeparam>
            /// <param name="info"></param>
            /// <returns></returns>
            private static (string, List<KeyValuePair<string, object>>) GetValues<TInfo>(TInfo info)
            {
                List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
                Type type = info.GetType();
                PropertyInfo[] pros = type.GetProperties();
                foreach (var item in pros)
                {
                    var name = GetDisplayNameValue(item.GetCustomAttributesData());
                    var value = GetPropertyInfoValue(item, info);
                    list.Add(new KeyValuePair<string, object>(name, value));
                }
                return
                    (GetDisplayNameValue(info.GetType().GetCustomAttributesData()),
                    list);
            }
    

    反射获取信息


    上面的工具方法定义后,我们来设置不同的方法获取不同的信息。

            /// <summary>
            /// 获取程序运行资源信息
            /// </summary>
            /// <returns></returns>
            public static (string, List<KeyValuePair<string, object>>) GetApplicationRunInfo()
            {
                ApplicationRunInfo info = new ApplicationRunInfo();
                return GetValues(info);
            }
    
            /// <summary>
            /// 获取系统运行平台信息
            /// </summary>
            /// <returns></returns>
            public static (string, List<KeyValuePair<string, object>>) GetSystemPlatformInfo()
            {
                SystemPlatformInfo info = new SystemPlatformInfo();
                return GetValues(info);
            }
    
            /// <summary>
            /// 获取系统运行环境信息
            /// </summary>
            /// <returns></returns>
            public static (string, List<KeyValuePair<string, object>>) GetSystemRunEvnInfo()
            {
                SystemRunEvnInfo info = new SystemRunEvnInfo();
                return GetValues(info);
            }
    

    还有一个方法获取环境变量的,不需要利用上面的类型-属性来操作,可以直接封装到方法中。

            /// <summary>
            /// 获取系统全部环境变量
            /// </summary>
            /// <returns></returns>
            public static (string, List<KeyValuePair<string, object>>) GetEnvironmentVariables()
            {
                List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
                IDictionary environmentVariables = Environment.GetEnvironmentVariables();
                foreach (DictionaryEntry de in environmentVariables)
                {
                    list.Add(new KeyValuePair<string, object>(de.Key.ToString(), de.Value));
                }
                return ("系统环境变量", list);
            }
    

    使用

    我们在 Program 中,这些写就可以输出所有信息了

            static void Main(string[] args)
            {
                var a = EnvironmentInfo.GetApplicationRunInfo();
                var b = EnvironmentInfo.GetSystemPlatformInfo();
                var c = EnvironmentInfo.GetSystemRunEvnInfo();
                var d = EnvironmentInfo.GetEnvironmentVariables();
                ConsoleInfo(a.Item1, a.Item2);
                ConsoleInfo(b.Item1, b.Item2);
                ConsoleInfo(c.Item1, c.Item2);
                ConsoleInfo(d.Item1, d.Item2);
                Console.ReadKey();
            }
            public static void ConsoleInfo(string title, List<KeyValuePair<string, object>> list)
            {
                Console.WriteLine("
    ***********" + title + "***********");
                foreach (var item in list)
                {
                    Console.WriteLine(item.Key + ":" + item.Value);
                }
            }
    

    在 Linux 中显示

    总结

    我以上使用了 类-属性 来作为获取功能,这样可以不必写很多方法去调用获取环境信息,属性就是数据。既方便序列化,又方便反射。
    同时,如果先拓展信息项,直接添加上去就行,反射直接全部拿到手。
    另外有个 Display 特性,专业用来显示信息项的。这样设置,可以为属性灵活设置别名,便于显示信息以及说明。

    笔者会继续带来更多反射的使用实例,融入到日常需求中。

  • 相关阅读:
    html-关于IE浏览器兼容性的问题,还有浏览器一直加载的问题。
    MyEclipse2015 javaweb项目从svn检出后变成java项目,clean之后不能编译,解决办法是
    Netty4 initAndRegister 解析
    Netty源码分析之NioEventLoop(转)
    深入NIO Socket实现机制(转)
    Netty组件介绍(转)
    Netty4 ServerBootstrap 初始化channelFactory ReflectiveChannelFactory
    netty4 ServerBootstrap.bind(port) debug
    Netty4详解三:Netty架构设计(转)
    主流开源流媒体服务器有哪些?(转)
  • 原文地址:https://www.cnblogs.com/whuanle/p/12381290.html
Copyright © 2020-2023  润新知