-
-
Notifications
You must be signed in to change notification settings - Fork 107
Placeholders and Nesting
string.Format references all args by index:
string.Format("{0} {1}", person.FirstName, person.LastName)
SmartFormat can do very the same:
Smart.Format("{0} {1}", person.FirstName, person.LastName)
SmartFormat takes indexed placeholders a step further, and lets you use named placeholders instead:
Smart.Format("{FirstName} {LastName}", person)
In fact, SmartFormat even supports several kinds of expressions (parameterless methods) to be used in placeholders:
Smart.Format("{FirstName.ToUpper} {LastName.ToLower}", person)
where ToUpper
is a parameterless method.
The {}
placeholder is a special placeholder that refers to the current scope. It is often used with conditionals, plurals, and lists, but can also be used to access the current scope directly. Read more about this in the Nesting section.
var data = new { City = new { Region = "river side"}};
// Instead of writing:
var result = Smart.Format("The city region is {City.Region}.", data);
// You can also use a nested Placeholder
// which gets the scope of the parent Placeholder:
result = Smart.Format("{City.Region:The city region is {}.}", data);
var person = new
{
Person = new
{
FirstName = "John",
LastName = "Long",
Address = new { City = "London", Street = "Main St" }
}
};
In SmartFormat, you can use nesting to avoid repetition, such as:
Smart.Format("City: {Person:{Address:{City}}, Name: {FirstName}}", person);
// Outputs: "City: London, Name: John"
Nesting is often used with conditionals, plurals, and lists:
var data = new
{
People = new List<object>
{
new {Name = "Name 1", Age = 20}
}
};
Smart.Format("There {People.Count:is a person.|are {} people.}", data);
// Outputs: "There is a person."
// After adding one more item to the People list:
// Outputs: "There are 2 people."
In the example above you'll notice the empty placeholder {}
. It uses the scope, which is People.Count
, and outputs its value.
Let's take a closer look at the Nested Placeholders example:
When using nested placeholders, it is necessary to understand the scope that SmartFormat will use. A nested placeholder always starts off with the scope of the item that contains it.
The root scope for the template above is Person, meaning that {Person.Address}
is equivalent to C# person.Person.Address
.
Within the nested area, however, the "scope" has changed to Person.Address
, so nested expressions like {Street}
are evaluated against Person.Address
.
To illustrate this, the following are all equivalent, while the last one is the shortest form:
{Person.Name} {Person.Address.City} {Person.Address.Street}
{Person.Name} {Person.Address:{City} {Street}}
{Person:{Name} {Address:{City} {Street}}}
Within any nested scope, you still have access to the outer scopes. For example:
{Person.Address:{Person.Name} {City} {Street}}
Here, {Person.Name}
, which is in the root scope, is still accessible from within the nested Person.Address
scope.
Note, that in the following sameple the property with name Threshold
is defined in the Override
scope, and also in the Settings
scope.
{
var settings = new
{
Settings = new
{
Maximum = 100,
Threshold = 1,
Override = new
{
Threshold = 99
}
}
};
var result = Smart.Format("OverrideThreshold = {Settings:{Override:{Threshold}}}", settings);
// result: "OverrideThreshold = 99"
Now, what happens if the Threshold
property is not defined in the Override
scope, but only in the Settings
scope?
var settings = new
{
Settings = new
{
Maximum = 100,
Threshold = 1,
Override = new
{
// Property does not exist
// Threshold = 99
}
}
};
// The first scope is Settings, the second is Override
var result = Smart.Format("Threshold = {Settings:{Override:{Threshold}}}", settings);
// result: "Threshold = 1"
In this case, SmartFormat will look for the Threshold
property in the Override
scope first. Since it does not exist there, it will fallback to the parents' scope, which is Settings
, and find the value 1
.
This fallback mechanism is useful when you want to override properties in a nested scope but still have a default value available in the parent scope.
Caution
The parent scope resolution can be a useful feature, but it can also lead to unexpected results if not used carefully.
The fallback only occurs for undefined properties. It does not apply to null
property values.
// Use Setttings.Threshold if Override.Threshold is null:
var result = Smart.Format("Threshold = {Settings:{Override:{Threshold:isnull:{Settings.Threshold}|{}}}}", settings);
Caution
The fallback mechanism only works for nested placeholders and Scoped Notation. It does not apply to Dot Notation.
- Syntax, Terminology
- Placeholders and Nesting
- string.Format Compatibility
- Character Literals in Format Strings
- HTML With CSS or JavaScript
- Data Source Extensions
- Default _ DefaultFormatter
- Lists _ ListFormatter
- Choose _ ChooseFormatter
- Condition _ ConditionalFormatter
- Null _ NullFormatter
- SubString _ SubStringFormatter
- RegEx _ IsMatchFormatter
- Pluralization _ PluralLocalizationFormatter
- Localization _ LocalizationFormatter
- Templates _ TemplateFormatter
- TimeSpan _ TimeFormatter
- XML _ XElementFormatter
- Extension Methods
- Home
- Common Pitfalls
- HTML with CSS or JavaScript
- Overview
- Main Features
- Formatters
- Extra Features
- Console and StringBuilder
- TemplateFormatter
- SmartSettings to control Smart.Format behavior
- Additional Info
- License