# Property bags

> Understand the role of property bags and the performance considerations when using them.

A property bag is a companion object for a given .NET object type. The bag contains a collection of properties for its companion type. You can use the property bag to efficiently traverse, access, and modify data for an instance of an object of the companion type.

## Generating property bags

Unity uses one of the following methods to generate property bags for a type:

* **Reflection**: By default, Unity uses reflection to generate the property bag for a type. Reflection offers convenience and occurs [lazily](https://learn.microsoft.com/en-us/dotnet/framework/performance/lazy-initialization) only once per type when a property bag hasn't been registered yet.

* **Code generation**: To enhance performance, you can opt-in to code generation. To generate property bags by code generation, you must:

  * Annotate the type with the [`[Unity.Properties.GeneratePropertyBag]`](/engine/6000.0/script-reference/unity/properties/generatepropertybagattribute.md) attribute.
  * Annotate the assembly with the [`[assembly: Unity.Properties.GeneratePropertyBagsForAssembly]`](/engine/6000.0/script-reference/unity/properties/generatepropertybagsforassemblyattribute.md) attribute. Code-generated property bags are automatically registered when the domain is loaded.

## Included members

Both methods of generating property bags generate properties for the following type members:

* Public fields.
* Private or internal fields tagged with [`[SerializeField]`](/engine/6000.0/script-reference/unityengine/serializefield.md), [`[SerializeReference]`](/engine/6000.0/script-reference/unityengine/serializereference.md), or [`[CreateProperty]`](/engine/6000.0/script-reference/unity/properties/createpropertyattribute.md).
* Public, private, or internal properties tagged with [`[Unity.Properties.CreateProperty]`](/engine/6000.0/script-reference/unity/properties/createpropertyattribute.md).

Adding the [`[DontCreateProperty]`](/engine/6000.0/script-reference/unity/properties/dontcreatepropertyattribute.md) attribute to public, private, or internal fields excludes them from the property bag.

A generated property is read-only if the field is read-only or the property only has a getter. You can also use [`[Unity.Properties.CreateProperty(ReadOnly = true)]`](/engine/6000.0/script-reference/unity/properties/dontcreatepropertyattribute.md) to make a generated property read-only.

The following example combines the Unity serialization system with the Unity Properties system:

\[!code-cs[](/engine/6000.0/manual/property-bag-example.md)]

Creating properties in the property bag using serialization attributes for convenience is not always the preferred approach. [Unity's serialization system](/engine/6000.0/manual/scripting/compilation-and-code-reload/script-serialization.md) can only operate on fields and auto-properties, which makes it challenging to validate or propagate changes effectively.

Unlike the Unity serialization system, the properties within a property bag don't qualify as value types with [`[SerializeField]`](/engine/6000.0/script-reference/unityengine/serializefield.md). Instead, struct types are recognized as value types, whereas class types are recognized as references.

In Unity serialization, although polymorphism is supported, you must use the [`[SerializeReference]`](/engine/6000.0/script-reference/unityengine/serializereference.md) attribute to explicitly opt in. Otherwise, instances are serialized as value types. Note that [`UnityEngine.Object`](/engine/6000.0/script-reference/unityengine/object.md) types are an exception to this rule and are automatically serialized as reference types.

## Performance considerations

Generating property bags by reflection can introduce performance overhead the first time you request a property bag for a given container type. Creating properties for field members through reflection can allocate memory and increase garbage collector overhead in IL2CPP builds.

To avoid reflection and improve performance, [generate property bags by code generation](#generating) instead. However, be aware that this runtime optimization can come at the cost of longer compilation times. To enable the property bag to access internal and private fields and properties, make the type `partial`.

## Additional resources

* [Property visitors](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors.md)
* [Property paths](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-paths.md)
* [Use `PropertyVisitor` to create a property visitor](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-property-visitor.md)
* [Use low-level APIs to create a property visitor](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-low-level-api.md)
