🎀🎀🎀代码之美系列目录🎀🎀🎀
一、C# 命名规则规范
二、C# 代码约定规范
三、C# 参数类型约束
四、浅析 B/S 应用程序体系结构原则
五、浅析 C# Async 和 Await
六、浅析 ASP.NET Core SignalR 双工通信
七、浅析 ASP.NET Core 和 MongoDB 创建 Web API
八、浅析 ASP.NET Web UI 框架 Razor Pages/MVC/Web API/Blazor
九、如何使用 MiniProfiler WebAPI 分析工具
十、浅析 .NET Core 中各种 Filter
十一、C#.Net筑基-类型系统
十二、C#.Net 筑基-运算符
十三、C#.Net筑基-解密委托与事件
十四、C#.Net筑基-集合知识大全
十五、C#.Net筑基 - 常见类型
十六、C#.NET体系图文概述—2024最全总结
十七、C# 强大无匹的模式匹配,让代码更加优雅
十八、C# 中的记录类型简介
十九、C# 异步编程模型【代码之美系列】
二十、C#高级篇 反射和属性详解【代码之美系列】
文章目录
- 🎀🎀🎀代码之美系列目录🎀🎀🎀
- 前言
- 一、需求场景分析
- 二、核心技术:反射(Reflection)
- 三、基础实现方案
- 3.1 核心代码实现
- 3.2 使用示例
- 3.3 输出结果
- 四、高级功能扩展
- 4.1 处理特殊字符和JSON模板
- 4.2 添加格式控制
- 4.3 性能优化建议
- 五、完整解决方案代码
- 六、实际应用场景
- 七、总结
前言
在日常开发中,我们经常遇到需要根据数据模型动态生成文本内容的需求,比如邮件模板、报告生成、消息通知等场景。传统的方式是为每个字段硬编码替换逻辑,但当模板或模型变更时,维护成本很高。本文将介绍如何使用 C#
反射机制实现一个灵活的模板引擎,能够根据 Model
字段名称自动匹配并替换模板中的占位符。
提示:以下是本篇文章正文内容,下面案例可供参考
一、需求场景分析
假设我们有一个用户信息模型 UserModel
:
public class UserModel
{public string Name { get; set; }public int Age { get; set; }public string Email { get; set; }public DateTime RegisterDate { get; set; }
}
需要生成如下欢迎邮件:
尊敬的{Name},您好!
您的年龄是{Age}岁,邮箱是{Email}。
您于{RegisterDate}注册成为我们的会员。
传统硬编码方式需要手动替换每个字段,而我们要实现的是:只需定义模板和模型,引擎自动完成所有字段的匹配和替换。
二、核心技术:反射(Reflection)
C#的反射机制允许我们在运行时:
- 获取类型信息
- 动态访问对象属性
- 调用方法等
关键API:
Type.GetProperty()
- 获取指定名称的属性PropertyInfo.GetValue()
- 获取属性值
三、基础实现方案
3.1 核心代码实现
public static string ReplaceTemplatePlaceholders(string template, object model)
{if (model == null) return template;var regex = new Regex(@"\{(\w+)\}");var matches = regex.Matches(template);foreach (Match match in matches){string propertyName = match.Groups[1].Value;PropertyInfo property = model.GetType().GetProperty(propertyName);if (property != null){object value = property.GetValue(model);template = template.Replace(match.Value, value?.ToString() ?? "");}}return template;
}
3.2 使用示例
var user = new UserModel
{Name = "张三",Age = 30,Email = "zhangsan@example.com",RegisterDate = DateTime.Now.AddDays(-10)
};string template = @"尊敬的{Name},您好!
您的年龄是{Age}岁,邮箱是{Email}。
您于{RegisterDate}注册成为我们的会员。";string result = ReplaceTemplatePlaceholders(template, user);
Console.WriteLine(result);
3.3 输出结果
尊敬的张三,您好!
您的年龄是30岁,邮箱是zhangsan@example.com。
您于2023/5/20 14:30:00注册成为我们的会员。
四、高级功能扩展
4.1 处理特殊字符和JSON模板
当模板中包含双引号或 JSON
格式时:
string template = """
{"user": {"name": "{Name}","age": {Age},"email": "{Email}","note": "这是\"用户数据\""}
}
""";
改进正则表达式避免匹配转义字符:
var regex = new Regex(@"(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_]*)\}(?!\})");
4.2 添加格式控制
支持类似 {RegisterDate:yyyy-MM-dd}
的格式:
var regex = new Regex(@"\{(\w+)(?::([^}]+))?\}");
// ...
if (property != null)
{object value = property.GetValue(model);string format = match.Groups[2].Success ? match.Groups[2].Value : null;string stringValue = format != null && value is IFormattable formattable ? formattable.ToString(format, null) : value?.ToString() ?? "";// ...
}
4.3 性能优化建议
缓存 PropertyInfo
:使用 ConcurrentDictionary
缓存已查找的属性
预编译正则表达式:添加 RegexOptions.Compiled
选项
使用 StringBuilder
:对于大模板提高替换效率
五、完整解决方案代码
using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;public class TemplateEngine
{private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache = new();private static readonly Regex _placeholderRegex = new(@"(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_]*)(?::([^}]+))?\}(?!\})", RegexOptions.Compiled);public static string Render(string template, object model){if (model == null) return template;var type = model.GetType();if (!_propertyCache.TryGetValue(type, out var properties)){properties = type.GetProperties();_propertyCache.TryAdd(type, properties);}var propertyLookup = properties.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);return _placeholderRegex.Replace(template, match =>{string propName = match.Groups[1].Value;string format = match.Groups[2].Value;if (!propertyLookup.TryGetValue(propName, out var property))return match.Value;object value = property.GetValue(model);if (value == null) return string.Empty;return !string.IsNullOrEmpty(format) && value is IFormattable formattable ? formattable.ToString(format, null) : value.ToString();});}
}
六、实际应用场景
- 邮件通知系统:根据不同事件动态生成邮件内容
- 报表生成:根据数据模型自动填充报表模板
- 多语言支持:根据不同语言的模板生成内容
- 合同生成:自动填充合同模板中的客户信息
七、总结
本文实现的模板引擎具有以下优势:
- 灵活性:模板与代码解耦,修改模板无需重新编译
- 可维护性:添加新字段只需修改模板和模型
- 扩展性:支持格式控制、嵌套对象等高级功能
- 性能优化:通过缓存和预编译提升执行效率