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关键字,可以创建更加高效和组织的代码结构。记住要适度使用,避免过度依赖静态成员导致代码难以测试和维护。