Version: 2023.2
言語: 日本語
Property bags
Property paths

Property visitors

Property visitors are algorithms built on top of the Properties API.

Concept

You can use visitors to add functionality to types without the need for direct modifications. You can create highly generic visitors to control both the algorithm itself and the visitation process. This differs from the classic implementation of the visitor pattern, where the visitation typically occurs on a known ahead-of-time type structure. It enables features like serialization, inspector-like UI generation, among others.

The following is the basic pattern of visitors. It takes place on the property bags and property companion objects.

  1. An instance of a type accepts a visitor.
  2. The visitor visits the the property bag of the instance.
  3. The property bag can loop through its properties and accept the visitor.

Create a property visitor to get properties

You can use the following approaches to create your visitors to get properties:

The first approach is the easiest way to get started. However, for more extensive customization of the visitation behavior for both the property bags and the properties, use the second approach, which offers greater flexibility and the potential for performance improvements.

The following example uses the PropertyVisitor class to create a simple visitor that gets the properties of a given type that are tagged with a certain attribute:

public class BindableAttribute
    : Attribute
{
}

public class GatherBindablePropertiesVisitor
    : PropertyVisitor
{
    public List<PropertyPath> BindableProperties { get; set; }

    protected override void VisitProperty<TContainer, TValue>(Property<TContainer, TValue> property, ref TContainer container, ref TValue value)
    {
        if (property.HasAttribute<BindableAttribute>())
            BindableProperties.Add(PropertyPath.AppendProperty(default, property));
    }
}

The following is the equivalent example that uses the IPropertyBagVisitor interface to create the visitor:

public class BindableAttribute
    : Attribute
{
}

public class GatherBindablePropertiesVisitor
    : IPropertyBagVisitor
{
    public List<PropertyPath> BindableProperties { get; set; }

    void IPropertyBagVisitor.Visit<TContainer>(IPropertyBag<TContainer> propertyBag, ref TContainer container)
    {
        // Loop through the properties of the container object.
        foreach (var property in propertyBag.GetProperties(ref container))
        {
            if (property.HasAttribute<BindableAttribute>())
                BindableProperties.Add(PropertyPath.AppendProperty(default, property));
        }
    }
}

The low-level visitor is more performant because it doesn’t need to loop through all the properties of the property bag and extract their value. You can also use low-level visitors to visit properties that aren’t part of a property bag.

パフォーマンスの考慮点

Property bags, properties and visitors are all implemented using generic types so that we can remain as strongly-typed as possible and, in many cases, avoid boxing allocations during visitation. The trade-off of using generic types is that the JIT compiler will generate the IL for a given method the first time it is called. This can result in a slower execution the first time a visitor is accepted on an object.

その他の参考資料

Property bags
Property paths