.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("\n***********" + title + "***********");
            foreach (var item in list)
            {
                Console.WriteLine(item.Key + ":" + item.Value);
            }
        }

在 Linux 中顯示

總結

我以上使用了 類-屬性 來作為獲取功能,這樣可以不必寫很多方法去調用獲取環境信息,屬性就是數據。既方便序列化,又方便反射。
同時,如果先拓展信息項,直接添加上去就行,反射直接全部拿到手。
另外有個 Display 特性,專業用來顯示信息項的。這樣設置,可以為屬性靈活設置別名,便於顯示信息以及說明。

筆者會繼續帶來更多反射的使用實例,融入到日常需求中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM