在开发过程中,我们经常需要使用缓存来提高应用程序的性能。本文将介绍如何使用C#实现一个简单的内存缓存系统,它模仿了Redis的部分基本功能
功能:
- 基本的键值存储
- 支持过期时间
- 支持泛型类型
- Hash 类型操作
- 线程安全
- 清理过期项
优点:
- 不依赖第三方库
- 实现简单
- 内存操作,速度快
- 支持基本的 Redis 功能
限制:
- 数据存储在内存中,程序重启后数据会丢失
- 不支持分布式
- 功能相对简单
代码实现:
using System.Collections.Concurrent;
namespace SimpleRedisApp
{
public interface ISimpleRedis
{
bool Set<T>(string key, T value, TimeSpan? expiry = null);
T Get<T>(string key);
bool Delete(string key);
bool Exists(string key);
List<string> GetAllKeys();
bool HashSet(string key, string field, object value);
T HashGet<T>(string key, string field);
void RemoveExpiredItems();
}
/// <summary>
/// 简单的内存缓存实现
/// </summary>
public class SimpleRedis : ISimpleRedis
{
// 使用ConcurrentDictionary保证线程安全
private static readonly ConcurrentDictionary<string, CacheItem> Cache = new ConcurrentDictionary<string, CacheItem>();
// 缓存项类,包含值和过期时间
private class CacheItem
{
public object Value { get; set; }
public DateTime? ExpireTime { get; set; }
}
/// <summary>
/// 设置缓存
/// </summary>
public bool Set<T>(string key, T value, TimeSpan? expiry = null)
{
var item = new CacheItem
{
Value = value,
ExpireTime = expiry.HasValue ? DateTime.Now.Add(expiry.Value) : null
};
Cache.AddOrUpdate(key, item, (k, old) => item);
return true;
}
/// <summary>
/// 获取缓存
/// </summary>
public T Get<T>(string key)
{
if (Cache.TryGetValue(key, out CacheItem item))
{
if (item.ExpireTime.HasValue && item.ExpireTime.Value < DateTime.Now)
{
// 已过期,删除并返回默认值
Cache.TryRemove(key, out _);
return default(T);
}
return (T)item.Value;
}
return default(T);
}
/// <summary>
/// 删除缓存
/// </summary>
public bool Delete(string key)
{
return Cache.TryRemove(key, out _);
}
/// <summary>
/// 判断键是否存在
/// </summary>
public bool Exists(string key)
{
return Cache.ContainsKey(key) &&
(!Cache[key].ExpireTime.HasValue || Cache[key].ExpireTime.Value > DateTime.Now);
}
/// <summary>
/// 清空所有缓存
/// </summary>
public void Clear()
{
Cache.Clear();
}
/// <summary>
/// 获取所有键
/// </summary>
public List<string> GetAllKeys()
{
return Cache.Keys.ToList();
}
/// <summary>
/// 设置Hash
/// </summary>
public bool HashSet(string key, string field, object value)
{
var hash = Get<Dictionary<string, object>>(key) ?? new Dictionary<string, object>();
hash[field] = value;
return Set(key, hash);
}
/// <summary>
/// 获取Hash
/// </summary>
public T HashGet<T>(string key, string field)
{
var hash = Get<Dictionary<string, object>>(key);
if (hash != null && hash.ContainsKey(field))
{
return (T)hash[field];
}
return default(T);
}
/// <summary>
/// 删除过期的缓存项
/// </summary>
public void RemoveExpiredItems()
{
var now = DateTime.Now;
var expiredKeys = Cache.Where(kvp =>
kvp.Value.ExpireTime.HasValue &&
kvp.Value.ExpireTime.Value < now)
.Select(kvp => kvp.Key)
.ToList();
foreach (var key in expiredKeys)
{
Cache.TryRemove(key, out _);
}
}
}
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var redis = new SimpleRedis();
// 字符串操作
redis.Set("name", "张三", TimeSpan.FromMinutes(1));
var name = redis.Get<string>("name");
Console.WriteLine($"Name: {name}");
// 对象操作
var user = new User { Name = "李四", Age = 25 };
redis.Set("user:1", user);
var savedUser = redis.Get<User>("user:1");
Console.WriteLine($"User: {savedUser.Name}, {savedUser.Age}");
// Hash操作
redis.HashSet("user:2", "name", "王五");
redis.HashSet("user:2", "age", 30);
var userName = redis.HashGet<string>("user:2", "name");
var userAge = redis.HashGet<int>("user:2", "age");
Console.WriteLine($"Hash User: {userName}, {userAge}");
// 删除操作
redis.Delete("name");
// 检查键是否存在
var exists = redis.Exists("user:1");
Console.WriteLine($"user:1 exists: {exists}");
// 获取所有键
var allKeys = redis.GetAllKeys();
Console.WriteLine($"All keys: {string.Join(", ", allKeys)}");
// 存入缓存,设置过期时间为30分钟
redis.Set($"user:3", user, TimeSpan.FromMinutes(30));
// 清理过期项
redis.RemoveExpiredItems();
Console.ReadKey();
}
}
}
可以写个定时器定期清理过期项