SoFunction
Updated on 2025-04-14

How to automatically match and replace values ​​based on Model field names

Preface

In daily development, we often encounter the need to dynamically generate text content based on the data model, such as email templates, report generation, message notifications and other scenarios. The traditional way is to hardcode the replacement logic for each field, but the maintenance costs are high when the template or model changes. This article will explain how to use the C# reflection mechanism to implement a flexible template engine that can automatically match and replace placeholders in the template based on the Model field name.

1. Requirement scenario analysis

Suppose we have a user information 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; }
}

The following welcome email is required:

Hello, dear {Name}!
Your age is {Age} years old and your email is {Email}.
You are registered as a member of us at {RegisterDate}.

The traditional hard-coded method requires manual replacement of each field, and what we want to achieve is: just define the template and model, and the engine automatically completes the matching and replacement of all fields.

2. Core technology: Reflection

The reflection mechanism of C# allows us to run at:

  • Get type information
  • Dynamic access to object properties
  • Calling methods, etc.

Key APIs:

  • () - Get the attribute of the specified name
  • () - Get attribute value

3. Basic implementation plan

3.1 Core code implementation

public static string ReplaceTemplatePlaceholders(string template, object model)
{
    if (model == null) return template;

    var regex = new Regex(@"\{(\w+)\}");
    var matches = (template);

    foreach (Match match in matches)
    {
        string propertyName = [1].Value;
        PropertyInfo property = ().GetProperty(propertyName);
        if (property != null)
        {
            object value = (model);
            template = (, value?.ToString() ?? "");
        }
    }

    return template;
}

3.2 Use examples

var user = new UserModel
{
    Name = "Zhang San",
    Age = 30,
    Email = "zhangsan@",
    RegisterDate = (-10)
};

string template = @"Dear{Name},Hello!
Your age is{Age}age,The email address is{Email}。
You{RegisterDate}Register as our member。";

string result = ReplaceTemplatePlaceholders(template, user);
(result);

3.3 Output results

Dear Zhang San, hello!
Your age is 30 years old and your email address is zhangsan@.
You registered as our member at 2023/5/20 14:30:00.

4. Advanced function expansion

4.1 Handling special characters and JSON templates

When the template contains double quotes or JSON format:

string template = """
{
    "user": {
        "name": "{Name}",
        "age": {Age},
        "email": "{Email}",
        "note": "This is\"User Data\""
    }
}
""";

Improve regular expressions to avoid matching escaped characters:

var regex = new Regex(@"(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_]*)\}(?!\})");

4.2 Add format control

Supports formats similar to {RegisterDate:yyyy-MM-dd}:

var regex = new Regex(@"\{(\w+)(?::([^}]+))?\}");
// ...
if (property != null)
{
    object value = (model);
    string format = [2].Success ? [2].Value : null;
    string stringValue = format != null && value is IFormattable formattable 
        ? (format, null) 
        : value?.ToString() ?? "";
    // ...
}

4.3 Performance optimization suggestions

Cache PropertyInfo: Use ConcurrentDictionary to cache the searched properties

Precompiled regular expressions: Add options

Use StringBuilder: Improve replacement efficiency for large templates

5. Complete solution code

using System;
using ;
using ;
using ;
using ;

public class TemplateEngine
{
    private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache = new();
    private static readonly Regex _placeholderRegex = new(@"(?<!\{)\{([a-zA-Z_][a-zA-Z0-9_]*)(?::([^}]+))?\}(?!\})", );

    public static string Render(string template, object model)
    {
        if (model == null) return template;
        
        var type = ();
        if (!_propertyCache.TryGetValue(type, out var properties))
        {
            properties = ();
            _propertyCache.TryAdd(type, properties);
        }

        var propertyLookup = (p => , );
        
        return _placeholderRegex.Replace(template, match =>
        {
            string propName = [1].Value;
            string format = [2].Value;

            if (!(propName, out var property))
                return ;

            object value = (model);
            if (value == null) return ;

            return !(format) && value is IFormattable formattable 
                ? (format, null) 
                : ();
        });
    }
}

6. Practical application scenarios

Email notification system: dynamically generate email content based on different events

Report generation: Automatically fill report templates according to data model

Multilingual support: generate content based on templates in different languages

Contract generation: Automatically fill customer information in contract templates

7. Summary

The template engine implemented in this article has the following advantages:

  • Flexibility: Decoupling the template from the code, modifying the template without recompiling it
  • Maintainability: Adding new fields requires just modifying the template and model
  • Extensibility: Supports advanced functions such as format control and nested objects
  • Performance optimization: Improve execution efficiency through caching and precompilation

This is the article about how C# automatically matches and replaces values ​​according to Model field names. For more related content related to C# automatic matching and replacement, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!