C#实现简单的内存缓存

在开发过程中,我们经常需要使用缓存来提高应用程序的性能。本文将介绍如何使用C#实现一个简单的内存缓存系统,它模仿了Redis的部分基本功能

功能:

  • 基本的键值存储
  • 支持过期时间
  • 支持泛型类型
  • Hash 类型操作
  • 线程安全
  • 清理过期项

优点:

  • 不依赖第三方库
  • 实现简单
  • 内存操作,速度快
  • 支持基本的 Redis 功能

限制:

  • 数据存储在内存中,程序重启后数据会丢失
  • 不支持分布式
  • 功能相对简单

代码实现:

cs 复制代码
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();
        }
    }
}

可以写个定时器定期清理过期项

相关推荐
妮妮喔妮10 分钟前
Go的垃圾回收
开发语言·后端·golang
emma羊羊2 小时前
【Redis】
数据库·redis·缓存
lang201509282 小时前
Spring Boot构建RESTful服务与Actuator监控
spring boot·后端·restful
向上的车轮3 小时前
无需云服务的家庭相册:OpenHarmony 上的 Rust 实践
开发语言·后端·rust
“抚琴”的人4 小时前
C# 取消机制(CancellationTokenSource/CancellationToken)
开发语言·c#·wpf·1024程序员节·取消机制
程序猿小蒜5 小时前
基于springboot的车辆管理系统设计与实现
java·数据库·spring boot·后端·spring·oracle
90后的晨仔5 小时前
Java后端开发:从零构建企业级应用的完整架构与技术栈详解
后端
helloworddm6 小时前
Orleans Grain Directory 系统综合分析文档
c#·1024程序员节
我命由我123456 小时前
Spring Cloud - Spring Cloud 声明式接口调用(Fiegn 声明式接口调用概述、Fiegn 使用)
java·后端·spring·spring cloud·微服务·架构·java-ee
canonical_entropy6 小时前
领域驱动设计(DDD)中聚合根的最主要职责真的是维护一致性吗?
后端·架构·领域驱动设计