Home > Software design >  Format a string with dynamic "binding expression" in C#
Format a string with dynamic "binding expression" in C#

Time:09-21

I'm thinking of this a lot like MVVM one way binding in AngularJS. I have an object (a "model") with a few properties and a few methods - something like

{
    "firstName": "John",
    "lastName": "Doe",
    "random": () => Random.Next(),
    "formatDate": (fmt, value) => new DateTime(value).ToString(fmt)
}

I'd like to define a format string which can access values from the model or call methods from it and get back the formatted string. In AngularJS I would use an expression like this

Hello {firstName} {lastName}. Today is {formatDate('d', new Date())}.

Is there a way to do something similar in C# (.NET 5)? I'm looking to do this on strings.

Here are the ideas I've come up with and the problems with them

  1. WPF / XAML. This is a ton of overhead I don't care about. I only want to format strings.
  2. Roslyn. This requires me to write the format expressions as valid C#. It's also a lot of work.
  3. Formattable strings / ICustomFormatter. This doesn't have support for passing a dynamic model or for method calls.

EDIT

Here's a sample of what the calling code might look like

var formatString = person.Tenant.WelcomeMessageFormat;
var model = new
{
    FirstName = person.FirstName,
    LastName = person.LastName,
    Random = () => Random.Next(),
    FormatDate = (fmt, value) => new DateTime(value).ToString(fmt)
};
var message = ParseFormatString(formatString, model);
SendMessage(message);

// .....

public string ParseFormatString(string format, object model)
{
    // what goes here?
}

CodePudding user response:

Are you looking for a templating library? That seems to be what you are describing. Here is an sample from the web http://r3c.github.io/cottle/

CodePudding user response:

This is pretty much a duplicate of Dynamic string interpolation but here's the dotnet core answer.

Install nuget package System.Linq.Dynamic.Core


using System;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

using DynLinq = System.Linq.Dynamic;

namespace aaq
{
    class Model
    {
        private Random _random = new Random();
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Random => _random.Next();
        public string FormatDate(string format, DateTime value) => value.ToString(format);
    };

    class Program
    {
        static void Main(string[] args)
        {
            var m = new Model()
            {
                FirstName = "firstly",
                LastName = "lastly",
            };

            Console.WriteLine(ReplaceMacro("a", m));
            Console.WriteLine(ReplaceMacro("hello {FirstName} {LastName}", m));
            Console.WriteLine(ReplaceMacro("date: {FormatDate(String.Empty, DateTime.Now)}", m));
        }

        static string ReplaceMacro(string value, Model m)
        {
            return Regex.Replace(value, @"{(?<exp>[^}] )}", match => {
                var p = Expression.Parameter(typeof(Model), "Model");
                var e = DynLinq.Core.DynamicExpressionParser.ParseLambda(new[] { p }, null, match.Groups["exp"].Value);
                return (e.Compile().DynamicInvoke(m) ?? "").ToString();
            });
        }
    }
}

Console output:

a
hello firstly lastly
date: 9/20/2022 12:05:23 PM
  • Related