# プロパティビジター

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

プロパティビジターは、Properties API の上にビルドされたアルゴリズムです。

## コンセプト##create-a-property-visitor-to-get-properties

ビジターを使用すると、直接変更することなく型に機能を追加できます。高度にジェネリックなビジターを作成して、アルゴリズム自体と訪問プロセスの両方を制御できます。これは、訪問が通常は既知の事前型構造で発生する、ビジターパターンの従来の実装とは異なります。[シリアル化](https://docs.unity3d.com/Packages/com.unity.serialization@3.1/manual/index.html)、インスペクターのような UI 生成などの機能が可能になります。

以下は、ビジターの基本的なパターンです。これは、プロパティバッグとプロパティコンパニオンオブジェクトで発生します。

1. 型のインスタンスがビジターを**受け入れます**。
2. ビジターがインスタンスのプロパティバッグを**訪問**します。
3. プロパティバッグは、そのプロパティをループし、ビジターを**受け入れる**ことができます。

## プロパティビジターを作成してプロパティを取得する##performance-considerations

以下のアプローチを使用して、ビジターを作成してプロパティを取得できます。

* [`Unity.Properties.PropertyVisitor`](/engine/6000.0/script-reference/unity-properties/property-visitor.md) 基本クラスを使用します。例については、[`PropertyVisitor` を使用してプロパティビジターを作成する](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-propertyvisitor.md) を参照してください。
* [`IPropertyBagVisitor`](/engine/6000.0/script-reference/unity-properties/i-property-bag-visitor.md) インターフェースと [`IPropertyVisitor`](/engine/6000.0/script-reference/unity-properties/i-property-visitor.md) インターフェースを実装します。例については、[低レベル API を使用してプロパティビジターを作成する](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-low-level-api.md) を参照してください。

最初のアプローチは、使用を開始する最も簡単な方法です。ただし、プロパティバッグとプロパティの両方の訪問動作をより広範囲にカスタマイズするには、柔軟性が高くパフォーマンスが向上する可能性がある 2 番目のアプローチを使用します。

以下の例では、[`PropertyVisitor`](/engine/6000.0/script-reference/unity-properties/property-visitor.md) クラスを使用して、特定の属性でタグ付けされた特定の型のプロパティを取得する単純なビジターを作成します。

```lang-csharp
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));
    }
}
```

以下は、`IPropertyBagVisitor` インターフェースを使用してビジターを作成する同等の例です。

```lang-csharp
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));
        }
    }
}
```

プロパティバッグのすべてのプロパティをループして値を抽出する必要がないため、低レベルのビジターはよりパフォーマンスが高くなります。プロパティバッグの一部ではないプロパティにアクセスするために低レベルのビジターを使用することもできます。

## パフォーマンスの考慮点##additional-resources

プロパティバッグ、プロパティ、ビジターはすべてジェネリック型を使用して実装されます。これにより、できる限り強い型付けを維持し、多くの場合、訪問中にボックス化割り当てを避けることができます。ジェネリック型を使用するトレードオフは、特定のメソッドが最初に呼び出されたときに JIT コンパイラーがそのメソッドの IL を生成することです。その結果、オブジェクトに対して初めてビジターが受け入れられたときに実行が遅くなる可能性があります。

## 追加リソース

* [プロパティバッグ](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-bags.md)
* [プロパティパス](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-paths.md)
* [`PropertyVisitor` を使用してプロパティビジターを作成する](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-propertyvisitor.md)
* [低レベル API を使用してプロパティビジターを作成する](/engine/6000.0/manual/scripting/object-oriented-development/properties/property-visitors-low-level-api.md)
