# Properties source

> Read a member by name from the current value through the Unity.Properties data model.

Read a member by name from the current value through the Unity.Properties data model.

The Properties source evaluates a named selector against the current object with `Unity.Properties`, the same data model that UI Toolkit data binding uses. It matches the selector to a member that Unity.Properties exposes and returns its value. It works with plain classes and structs, as well as `MonoBehaviour` fields, without registering a property bag in advance.

The Properties source is the default way members are read by name. It resolves the members that Unity.Properties exposes. When a selector does not match an exposed member, the source returns without a result and any later source in the formatter handles the selector.

When matching, `string` values are handled by the [String source](/engine/6000.7/manual/scripting/smart-strings/sources/string-source.md), so the Properties source ignores them.

Member matching is case-sensitive. When the formatter uses case-insensitive matching, a differently cased selector does not resolve through this source.

Use the nullable operator to return an empty result instead of an error when the current value is `null`, for example (`{Address?.City}`).

| Smart String                    | Argument                                             | Result                       |
| ------------------------------- | ---------------------------------------------------- | ---------------------------- |
| `{Name} reached level {Level}.` | `new PlayerData { Name = "Juan Pérez", Level = 12 }` | Juan Pérez reached level 12. |

```cs
var player = new PlayerData { Name = "Juan Pérez", Level = 12 };

            // "Juan Pérez reached level 12."
            Smart.Format("{Name} reached level {Level}.", player);
```

## Mark members so the Properties source can read them

The members the Properties source exposes follow Unity's serialization rules:

* Public fields.
* Private or internal fields marked with `[SerializeField]`.
* Members marked with `[CreateProperty]` or `[SerializeReference]`.

This includes non-public members that carry those attributes. Methods and plain, non-attributed properties are not exposed and do not resolve through this source. To read those, write a [custom source](/engine/6000.7/manual/scripting/smart-strings/sources/create-a-custom-source.md).

```cs
class Enemy
        {
            // A public field is visible with no attribute.
            public string Name = "Goblin";

            // A private field is visible when you mark it with [SerializeField].
            [SerializeField]
            int m_Health = 30;

            // A plain, non-attributed property is not visible.
            public int Score => 100;
        }
```

## Generate property bags to avoid reflection

By default, Unity.Properties builds a property bag for a type through reflection the first time it reads that type. To avoid the reflection, mark the type with `[GeneratePropertyBag]` and opt the assembly in with `[assembly: GeneratePropertyBagsForAssembly]`. The source generator then emits the property bag at compile time. This improves performance and is important on fully ahead-of-time compiled players, where the reflection fallback is limited.

```cs
[GeneratePropertyBag]
    public partial class Character
    {
        public string Name;
    }
```

## Additional resources

* [Create a custom source](/engine/6000.7/manual/scripting/smart-strings/sources/create-a-custom-source.md)
* [String source](/engine/6000.7/manual/scripting/smart-strings/sources/string-source.md)
* [Smart Strings](/engine/6000.7/manual/scripting/smart-strings.md)
