static关键字是C#中非常重要的概念,用于创建属于类型本身而不是类型实例的成员。
1. static关键字的基本概念
什么是static?
加上 static 的成员不再属于某个对象实例,而是直接属于类本身; 无论创建多少个实例,静态成员只有一份,通过类名即可访问。
static成员属于类型本身,而不是类型的实例
在程序运行期间,static成员只有一份副本
不需要创建对象实例即可访问static成员
static成员在类型第一次被使用时初始化
2. 静态类(Static Classes)
静态类的特点:
不能实例化(不能使用new创建对象)
只能包含静态成员
是密封的(不能被继承)
using System;
// 静态类定义
public static class MathUtilities
{
    // 静态字段
    public static readonly double PI = 3.14159;
    
    // 静态方法
    public static double CalculateCircleArea(double radius)
    {
        return PI * radius * radius;
    }
    
    public static int Add(int a, int b)
    {
        return a + b;
    }
    
    public static bool IsEven(int number)
    {
        return number % 2 == 0;
    }
}
class Program
{
    static void Main()
    {
        // 直接通过类名访问静态成员
        double area = MathUtilities.CalculateCircleArea(5.0);
        int sum = MathUtilities.Add(10, 20);
        bool isEven = MathUtilities.IsEven(15);
        
        Console.WriteLine($"圆面积: {area}");
        Console.WriteLine($"和: {sum}");
        Console.WriteLine($"15是偶数: {isEven}");
        
        // 编译错误:不能创建静态类的实例
        // MathUtilities utils = new MathUtilities(); // 错误!
    }
}3. 静态字段(Static Fields)
静态字段的特点:
所有实例共享同一个字段
在类第一次被使用时初始化
using System;
public class Counter
{
    // 实例字段 - 每个对象有自己的副本
    public int InstanceCount = 0;
    
    // 静态字段 - 所有对象共享同一个副本
    public static int StaticCount = 0;
    
    public Counter()
    {
        InstanceCount++;
        StaticCount++;
    }
    
    public void DisplayCounts()
    {
        Console.WriteLine($"实例计数: {InstanceCount}, 静态计数: {StaticCount}");
    }
}
class Program
{
    static void Main()
    {
        Counter c1 = new Counter();
        c1.DisplayCounts(); // 实例计数: 1, 静态计数: 1
        
        Counter c2 = new Counter();
        c2.DisplayCounts(); // 实例计数: 1, 静态计数: 2
        
        Counter c3 = new Counter();
        c3.DisplayCounts(); // 实例计数: 1, 静态计数: 3
        
        // 直接访问静态字段
        Console.WriteLine($"总计数器: {Counter.StaticCount}"); // 输出: 3
    }
}4. 静态方法(Static Methods)
静态方法的特点:
属于类本身,不属于任何实例
只能访问静态成员,不能直接访问实例成员
不需要创建对象即可调用
using System;
public class StringHelper
{
    // 实例方法 - 需要对象实例
    public string InstanceToUpper(string input)
    {
        return input.ToUpper();
    }
    
    // 静态方法 - 直接通过类名调用
    public static string StaticToUpper(string input)
    {
        return input.ToUpper();
    }
    
    // 静态方法只能访问静态成员
    private static string _prefix = "STATIC: ";
    
    public static string FormatMessage(string message)
    {
        return _prefix + message.ToUpper();
        // 编译错误:不能访问实例成员
        // return InstanceToUpper(message); // 错误!
    }
}
class Program
{
    static void Main()
    {
        // 调用静态方法 - 不需要创建对象
        string result1 = StringHelper.StaticToUpper("hello");
        string result2 = StringHelper.FormatMessage("world");
        
        Console.WriteLine(result1); // 输出: HELLO
        Console.WriteLine(result2); // 输出: STATIC: WORLD
        
        // 调用实例方法 - 需要创建对象
        StringHelper helper = new StringHelper();
        string result3 = helper.InstanceToUpper("hello");
        Console.WriteLine(result3); // 输出: HELLO
    }
}5. 静态属性(Static Properties)
using System;
using System.Collections.Generic;
public class AppSettings
{
    // 静态属性
    public static string AppName { get; set; } = "MyApplication";
    
    public static string Version { get; } = "1.0.0"; // 只读静态属性
    
    // 带有私有字段的静态属性
    private static int _userCount = 0;
    public static int UserCount
    {
        get { return _userCount; }
        private set { _userCount = value; } // 私有setter
    }
    
    public static void AddUser()
    {
        UserCount++;
    }
}
class Program
{
    static void Main()
    {
        // 访问静态属性
        Console.WriteLine($"应用名: {AppSettings.AppName}");
        Console.WriteLine($"版本: {AppSettings.Version}");
        Console.WriteLine($"用户数: {AppSettings.UserCount}");
        
        AppSettings.AddUser();
        AppSettings.AddUser();
        
        Console.WriteLine($"更新后用户数: {AppSettings.UserCount}");
        
        // 修改静态属性
        AppSettings.AppName = "AwesomeApp";
        Console.WriteLine($"新应用名: {AppSettings.AppName}");
    }
}6. 静态构造函数(Static Constructors)
静态构造函数的特点:
在类第一次被使用前自动调用
只能有一个静态构造函数
不能有访问修饰符
不能有参数
using System;
public class DatabaseManager
{
    // 静态字段
    private static readonly string ConnectionString;
    private static readonly DateTime InitializeTime;
    
    // 静态构造函数
    static DatabaseManager()
    {
        InitializeTime = DateTime.Now;
        ConnectionString = "Server=localhost;Database=MyApp;Trusted_Connection=true;";
        
        Console.WriteLine($"静态构造函数被调用,初始化时间: {InitializeTime}");
        Console.WriteLine("数据库连接已配置");
    }
    
    // 静态方法
    public static void ExecuteQuery(string query)
    {
        Console.WriteLine($"执行查询: {query}");
        Console.WriteLine($"使用连接字符串: {ConnectionString}");
    }
    
    public static void ShowInfo()
    {
        Console.WriteLine($"初始化时间: {InitializeTime}");
    }
}
class Program
{
    static void Main()
    {
        Console.WriteLine("程序开始");
        
        // 第一次使用类,触发静态构造函数
        DatabaseManager.ExecuteQuery("SELECT * FROM Users");
        
        // 不会再次调用静态构造函数
        DatabaseManager.ShowInfo();
    }
}7. 静态只读字段(Static Readonly Fields)
using System;
public class Constants
{
    // 编译时常量
    public const double PI = 3.14159;
    
    // 运行时常量(静态只读字段)
    public static readonly DateTime BuildTime;
    public static readonly string Version;
    
    // 静态构造函数中初始化
    static Constants()
    {
        BuildTime = DateTime.Now;
        Version = "2.1.0";
    }
    
    // 复杂类型的静态只读字段
    public static readonly List<string> SupportedLanguages = new List<string>
    {
        "C#", "Java", "Python", "JavaScript"
    };
}
class Program
{
    static void Main()
    {
        Console.WriteLine($"PI: {Constants.PI}");
        Console.WriteLine($"构建时间: {Constants.BuildTime}");
        Console.WriteLine($"版本: {Constants.Version}");
        
        Console.WriteLine("支持的语言:");
        foreach (string language in Constants.SupportedLanguages)
        {
            Console.WriteLine($" - {language}");
        }
        
        // 可以修改集合内容,但不能重新赋值
        Constants.SupportedLanguages.Add("Go");
        // Constants.SupportedLanguages = new List<string>(); // 错误!
    }
}8. 实际应用场景
场景1:工具类(Utility Classes)
using System;
using System.Text;
public static class StringExtensions
{
    public static string Reverse(this string input)
    {
        char[] chars = input.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
    
    public static bool IsPalindrome(this string input)
    {
        string cleaned = input.ToLower().Replace(" ", "");
        return cleaned == cleaned.Reverse();
    }
    
    public static string ToTitleCase(this string input)
    {
        if (string.IsNullOrEmpty(input))
            return input;
            
        string[] words = input.ToLower().Split(' ');
        StringBuilder result = new StringBuilder();
        
        foreach (string word in words)
        {
            if (word.Length > 0)
            {
                result.Append(char.ToUpper(word[0]) + word.Substring(1) + " ");
            }
        }
        
        return result.ToString().Trim();
    }
}
class Program
{
    static void Main()
    {
        string text = "hello world";
        
        Console.WriteLine($"原始: {text}");
        Console.WriteLine($"反转: {text.Reverse()}");
        Console.WriteLine($"标题格式: {text.ToTitleCase()}");
        Console.WriteLine($"'radar'是回文: {"radar".IsPalindrome()}");
        Console.WriteLine($"'hello'是回文: {"hello".IsPalindrome()}");
    }
}场景2:单例模式(Singleton Pattern)
using System;
public class Logger
{
    // 静态实例
    private static Logger _instance;
    private static readonly object _lockObject = new object();
    
    // 私有构造函数防止外部实例化
    private Logger()
    {
        Console.WriteLine("Logger实例已创建");
    }
    
    // 静态属性获取单例实例
    public static Logger Instance
    {
        get
        {
            // 双重检查锁定
            if (_instance == null)
            {
                lock (_lockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new Logger();
                    }
                }
            }
            return _instance;
        }
    }
    
    public void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
    }
}
class Program
{
    static void Main()
    {
        // 使用单例
        Logger logger1 = Logger.Instance;
        logger1.Log("第一条日志");
        
        Logger logger2 = Logger.Instance;
        logger2.Log("第二条日志");
        
        // 检查是否是同一个实例
        Console.WriteLine($"logger1 == logger2: {logger1 == logger2}"); // 输出: True
    }
}场景3:缓存管理
using System;
using System.Collections.Generic;
public static class Cache
{
    private static readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
    private static readonly object _lockObject = new object();
    
    public static void Set(string key, object value)
    {
        lock (_lockObject)
        {
            _cache[key] = value;
        }
    }
    
    public static T Get<T>(string key)
    {
        lock (_lockObject)
        {
            if (_cache.ContainsKey(key) && _cache[key] is T)
            {
                return (T)_cache[key];
            }
            return default(T);
        }
    }
    
    public static bool Contains(string key)
    {
        lock (_lockObject)
        {
            return _cache.ContainsKey(key);
        }
    }
    
    public static void Remove(string key)
    {
        lock (_lockObject)
        {
            _cache.Remove(key);
        }
    }
    
    public static void Clear()
    {
        lock (_lockObject)
        {
            _cache.Clear();
        }
    }
}
class Program
{
    static void Main()
    {
        // 使用静态缓存
        Cache.Set("UserName", "张三");
        Cache.Set("UserAge", 25);
        Cache.Set("LoginTime", DateTime.Now);
        
        string name = Cache.Get<string>("UserName");
        int age = Cache.Get<int>("UserAge");
        DateTime loginTime = Cache.Get<DateTime>("LoginTime");
        
        Console.WriteLine($"用户名: {name}");
        Console.WriteLine($"年龄: {age}");
        Console.WriteLine($"登录时间: {loginTime}");
        
        Console.WriteLine($"缓存中包含UserName: {Cache.Contains("UserName")}");
        
        Cache.Remove("UserAge");
        Console.WriteLine($"缓存中包含UserAge: {Cache.Contains("UserAge")}");
    }
}9. 最佳实践和注意事项
最佳实践:
使用场景:
工具类和方法
共享数据或状态
单例模式
常量定义
线程安全:
public static class ThreadSafeExample
{
    private static int _counter = 0;
    private static readonly object _lockObject = new object();
    
    // 线程安全的方法
    public static void IncrementCounter()
    {
        lock (_lockObject)
        {
            _counter++;
        }
    }
    
    public static int GetCounter()
    {
        lock (_lockObject)
        {
            return _counter;
        }
    }
}避免的问题:
过度使用静态成员可能导致紧耦合
静态变量在整个应用程序生命周期中存在,可能占用内存
测试困难(静态方法难以mock)
注意事项:
public class Example
{
    // 好的实践:工具方法设为静态
    public static bool IsValidEmail(string email)
    {
        return !string.IsNullOrEmpty(email) && email.Contains("@");
    }
    
    // 不好的实践:与对象状态相关的方法不应设为静态
    // public static string GetUserInfo() { } // 错误!
    
    // 好的实践:常量使用const或static readonly
    public const int MAX_USERS = 100;
    public static readonly DateTime StartupTime = DateTime.Now;
}
// 使用示例
class Program
{
    static void Main()
    {
        // 正确的使用
        bool isValid = Example.IsValidEmail("test@example.com");
        Console.WriteLine($"邮箱有效: {isValid}");
        
        // 访问常量
        Console.WriteLine($"最大用户数: {Example.MAX_USERS}");
        Console.WriteLine($"启动时间: {Example.StartupTime}");
    }
}10. 总结
static关键字在C#中用于创建属于类型本身的成员,具有以下特点:
静态类:不能实例化,只包含静态成员
静态成员:所有实例共享,通过类名访问
静态构造函数:在类第一次使用时自动调用
适用场景:工具类、单例模式、常量定义、共享数据
通过合理使用static关键字,可以创建更加高效和组织的代码结构。记住要适度使用,避免过度依赖静态成员导致代码难以测试和维护。