[Unity] Firestoreでネストされたクラスを利用する方法

IT・プログラミング

※ 本記事にはプロモーションが含まれています。

こんにちは! ねこです。

Firestore(Firebase)を Unity で利用する場合。

大体は、使用しやすくするためにクラスを定義して、その中に入れると思います。

しかし、下記のようにネストされたクラスの配列は、利用できません。

[FirestoreProperty]
public string name { get; set; } // OK.

[FirestoreProperty]
public List<Dictionary<string, object>> objects { get; set; } // OK.

[FirestoreProperty]
public List<Entity> entities { get; set; } // NG.

その場合の解決方法のひとつとして、リフレクションを利用する方法があります。

ネストしたいクラス(Entity)を、リフレクションを通じて Dictonary <string, object> に変換してしまえばいいわけです。

以下、サンプルコードを記載します。

リフレクションでの処理は、他の処理と比較して重いため、例えばループなどの処理に利用する場合は、記述に気をつけてください!

サンプルコード

ObjectExtension.cs

実際の変換処理を、Extension として実装したもの。

using System;
using System.Collections.Generic;
using System.Linq;

public static class ObjectExtension
{
    /// <summary>
    /// Get fields of the class as Dictonary<string, object>
    /// </summary>
    /// <param name="obj">Target object.</param>
    /// <typeparam name="T">The object type.</typeparam>
    /// <returns>All the fields as dictonary.</returns>
    public static Dictionary<string, object> GetFieldsAsDictonary<T>(this T obj)
    {
        return obj.GetType().GetFields()
            .ToDictionary(pi => pi.Name, pi => pi.GetValue(obj));
    }

    /// <summary>
    /// Convert dictionary to fields of class.
    /// </summary>
    /// <param name="dictionary">The dictionary before change.</param>
    /// <typeparam name="T">The class after change.</typeparam>
    /// <returns>The class object.</returns>
    public static T ConvertClassFields<T>(this Dictionary<string, object> dictionary) where T : new()
    {
        T obj = new T();
        var fields = obj.GetType().GetFields();
        foreach(var pair in dictionary)
        {
            var targetField = fields.FirstOrDefault(field => field.Name == pair.Key);
            if(targetField != default)
            {
                if(targetField.FieldType == typeof(Int32))
                {
                    targetField.SetValue(obj, Convert.ToInt32(pair.Value));
                }
                else if(targetField.FieldType == typeof(float))
                {
                    // 以下、必要な型変換の処理を行う。
                }
            }
        }
        return obj;
    }
}

Sample.cs

実際の利用方法を記述したサンプル。

using System.Collections.Generic;
using System.Linq;
using Firebase.Firestore;

[FirestoreData]
public class Sample
{
    /// <summary>
    /// The entities for Firestore.
    /// </summary>
    [FirestoreProperty]
    public List<Dictionary<string, object>> entities { get; set; }

    /// <summary>
    /// The entities.
    /// </summary>
    public List<Entity> Entities
    {
        get
        {
            return entities.Select(entity => entity.ConvertClassFields<Entity>()).ToList();
        }
        set
        {
            entities = value.Select(entity => entity.GetFieldsAsDictonary()).ToList();
        }
    }
}