Skip to content
axunonb edited this page Oct 2, 2022 · 5 revisions

1. NuGet Packages

a) Use SmartFormat.NET

For the migration from v2.x to v3 it's most convenient to reference the SmartFormat.NET package.

b) Available Packages

SmartFormat v3 comes with the following packages:

  • SmartFormat.NET - includes all SmartFormat extensions listed below. This is equivalent to the sole v2.x package.
  • SmartFormat - The "Core" package
  • SmartFormat.Extensions.Newtonsoft.Json - An ISource extension for Newtonsoft.Json variables
  • SmartFormat.Extensions.System.Text.Json - An ISource extension for System.Text.Json variables
  • SmartFormat.Extensions.Time - The formatter for DateTime, DateTimeOffset and TimeSpan variables
  • SmartFormat.Extensions.Xml - Brings the ISource extension for XElement variables, and a formatter for XElements

c) SmartFormat

SmartFormat is the core package. It comes with the most frequently used extensions built-in:

i. Source extensions:

  • GlobalVariablesSource
  • PersistentVariablesSource
  • StringSource ✔️
  • ListFormatter (implementing ISource) ✔️
  • DictionarySource ✔️
  • ValueTupleSource ✔️
  • ReflectionSource ✔️
  • DefaultSource ✔️
  • KeyValuePairSource ✔️

ii. Formatter extensions:

  • ListFormatter (implementing IFormatter) ✔️
  • PluralLocalizationFormatter ✔️
  • ConditionalFormatter ✔️
  • IsMatchFormatter ✔️
  • NullFormatter ✔️
  • LocalizationFormatter
  • TemplateFormatter
  • ChooseFormatter ✔️
  • SubStringFormatter ✔️
  • DefaultFormatter ✔️

Breaking change:

Note that only extensions marked (✔️) are included when calling Smart.CreateDefaultFormatter(...) and also when using Smart.Format(...). These default extensions differ from previously included extensions.

Coming from an old SmartFormat version?

In this case, please have in mind, that SmartFormat today has Smart.Default.Settings.CaseSensitivity = CaseSensitivityType.CaseSensitive. Also, parsing and formatting errors will throw by default. This can be modified in Settings.

Some extensions (like PersistentVariablesSource and TemplateFormatter) require configuration to be useful.

2. Formatter differences from v2 to v3

a) Curly Braces

Only curly braces {} can be used forPlaceholders in an input string.

b) Formatter Name

In v2.x more than one name could be used. In v3 the formatters have one name.

Formatter v2.x Names v3 Name CanAutoDetect *
ChooseFormatter choose, c choose Yes
ConditionalFormatter conditional, cond cond Yes
DefaultFormatter default, d d Yes
IsMatchFormatter ismatch ismatch No
IsNullFormatter n/a isnull No
ListFormatter list, l list Yes
LocalizationFormatter n/a L No
PluralLocalizationFormatter plural, p plural Yes
SubStringFormatter substr substr No
TemplateFormatter template, t t No
TimeFormatter timespan, time time Yes *
XElementFormatter xelement, xml, x xml Yes *

Formatters marked with * are part of separate NuGet packages.

The recommendation is to always use the formatter name. Is is more performant and eases debugging. However, formatters which are flagged with CanAutoDetect are able to detect whether they can handle a certain value.

It is possible to change the IFormatter.Name. Example:

// change the name from "cond" to "conditional"
Smart.Default.GetFormatterExtension<ChooseFormatter>().Name = "conditional";

3. Changes to commonly used APIs

a) Obsolete Elements

All obsolete element usage creates a compile time error including hints to resolve.

b) Formatting

a) Obsolete SmartObjects have now been removed. Use ValueTupleSource instead.

b) Class FormatCache has been removed. Caching is built into class Format, which is IDisposable. Usage:

// Auto-dispose or dispose manually
using format = new Parser().ParseFormat("The format string");

c) TimeFormatter has no constructor with an defaultTwoLetterLanguageName

d) PluralLocalizationFormatter has no constructor with an defaultTwoLetterLanguageName

e) TimeFormatter, PluralLocalizationFormatter, LocalizationFormatter: Culture is determined in this sequence:

  • Get the culture from the FormattingInfo.FormatterOptions, e.g. Smart.Format("{0:time(en):noless}), where "(en)" is the culture option.
  • Get the culture from the IFormatProvider argument (which may be a CultureInfo) to SmartFormatter.Format(IFormatProvider, string, object?[])
  • The CultureInfo.CurrentUICulture
  • PluralLocalizationFormatter: Note, that depending on the locale, expected arguments may be 2 or 3.

e) IFormatters all have only parameterless constructors. (For any initialization they're implementing the IIntializer interface.)

f) All custom IFormatters must implement the changed interface with properties Name and CanAutoDetect

g) SystemTime is now in the SmartFormat.Utilities namespace

h) JsonSource has been split into / replaced by NewtonsoftJsonSource and SystemTextJsonSource.

i) Interface for IOutput has changed

c) Parsing

a) Parser.ParseFormat() only has 1 argument for the input string

b) Parser.UseAlternativeEscapeChar(): Use Settings.StringFormatCompatibility true | false

c) Parser.UseBraceEscaping(): Use Settings.StringFormatCompatibility true | false

d) Add Extensions

Breaking change:

In v3 all WellKnownExtensionTypes.Sources and WellKnownExtensionTypes.Formatters are automatically inserted to the extension list at the place where they usually should be.

Any extension can, however, be inserted to the desired position in the extension list:

  • SmartFormatter.InsertExtension(int position, IFormatter sourceExtension)
  • SmartFormatter.InsertExtension(int position, IFormatter formatterExtension)

This can be useful especially when adding your custom extensions. You should call SmartFormatter.InsertExtension(...) after SmartFormatter.AddExtensions(...):

var formatter = new SmartFormatter()
    .AddExtensions(new ReflectionSource())
    .AddExtensions(new PluralLocalizationFormatter(), new DefaultFormatter())
    .InsertExtension(0, new MyCustomFormatter());

4. SmartSettings

For migration pay attention to the following aspects:

a) SmartSettings have been extended.

b) Don't change settings after the class instance was passed as an argument.

After a "smart class" is instanciated with SmartSettings, consider the settings as immutable. Later changes to the settings may or may not take effect.

Reasoning: As long as we're supporting older .Net Frameworks, we can't implement C# 9 Init-Only properties.

// DO
var sf = new SmartFormatter(new SmartSettings { CaseSensitivity = CaseSensitivityType.CaseInsensitive });
// DO NOT
var sf = new SmartFormatter();
sf.Settings.CaseSensitivity = CaseSensitivityType.CaseInsensitive;

5. Separate modes for "SmartFormat features" and "string.Format compatibility"

The mode can be set with SmartSettings.StringFormatCompatibility. By default, SmartSettings.StringFormatCompatibility is false.

Reasoning: The distinction was necessary because of syntax conflicts between SmartFormat extensions and string.Format. It brings a more concise and clear set of formatting rules and full string.Format compatibility even in "edge cases".

a) SmartFormat features mode

  • Brings the full set of features implemented in SmartFormat
  • Curly braces are escaped the Smart.Format way with \{ and \}.
  • As long as special characters (){}:\ are escaped with \, any character is allowed anywhere.

b) string.Format compatibility mode

  • SmartFormat acts as a drop-in replacement
  • On top, it allows for named placeholders besides indexed placeholders.
  • The Parser will not include the formatter name or formatting options. Like with string.Format, everything after the Selector separator (colon) is considered as format specifier.
  • Curly braces are escaped the string.Format way with {{ and }}. This is the reason for all limitations in string.Format compatibility mode
  • DefaultFormatter is the only formatter which will be invoked.
  • null will be output as string.Empty.

6. Integrate SmartFormat into a Custom Installer

In SmartFormat v2, the only assembly to include was SmartFormat.DLL.

In SmartFormat v3, include at least SmartFormat.DLL and SmartFormat.Zstring.DLL, along with assemblies from other required SmartFormat NuGet packages.

Clone this wiki locally