3

おはようございます。

ほぼすべての種類のシリアライズ可能なオブジェクトを *.INI ファイルにシリアライズする必要があります。メソッドがオブジェクトインスタンスからプロパティ情報を取得し、プリミティブ型のキー/値またはセクション + 複合型のキー/値を書き込む を実装しようとしています。
IFormattervoid Serialize(Stream, object)

シリアル化するオブジェクトの例として、このコードを取り上げます。

[Serializable]
public class EmployeeList
{
    #region Properties
    public List<Employee> Employees { get; private set; }

    public string Banana { get; set; }
    #endregion


    #region Constructors
    public EmployeeList()
    {
        Employees = new List<Employee>();
    }
    #endregion


    #region Public Methods
    public void Serialize()
    {
        IFormatter formatter = new IniFormatter();

        using (FileStream outputStream = File.Create("employees.ini"))
        {
            try
            {
                formatter.Serialize(outputStream, this);
            }
            catch (SerializationException ex)
            {
                //...
            }
        }
    }
    #endregion
}

[Serializable]
public class Employee
{
    #region Properties
    public string Name
    {
        get;
        set;
    }

    public Gender Gender
    {
        get;
        set;
    }

    public List<Role> Roles
    {
        get;
        set;
    }
    #endregion


    #region Constructors
    public Employee()
    {
    }
    #endregion
}

[Serializable]
public enum Gender
{
    Male,
    Female,
    Other
}

[Serializable]
public class Role
{
    public string Name
    {
        get;
        set;
    }

    public int Value
    {
        get;
        set;
    }


    #region Constructors
    public Role()
    {

    }
    #endregion
}

さて、リフレクションによってプロパティの名前と値を取得しようとしたので、すべてが些細なことのように思えました。System.Reflection.TargetParameterCountException反映しようとすると、継続的に取得されますList<Employee>(メソッドpi.GetValue(obj, null);を参照してください。どこにpiあるのかPropertyInfo)。

これは私のコードですIniFormatter:

public class IniFormatter : IFormatter
{
    #region Properties
    public ISurrogateSelector SurrogateSelector { get; set; }

    public SerializationBinder Binder { get; set; }

    public StreamingContext Context { get; set; }
    #endregion


    #region Constructors
    public IniFormatter()
    {
        Context = new StreamingContext(StreamingContextStates.All);
    }
    #endregion


    #region IFormatter Members
    public object Deserialize(Stream serializationStream)
    {
        throw new NotImplementedException();
    }

    public void Serialize(Stream serializationStream, object graph)
    {
        var propertyInfos = graph.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
        StreamWriter sw = new StreamWriter(serializationStream);

        foreach (var propertyInfo in propertyInfos)
        {
            if (!propertyInfo.CanRead)
            {
                continue;
            }

            if (Attribute.IsDefined(propertyInfo, typeof (NonSerializedAttribute)))
            {
                continue;
            }

            if (propertyInfo.PropertyType.IsPrimitive)
            {
                sw.WriteLine("{0}={1}", propertyInfo.Name, propertyInfo.GetValue(graph, null));
            }

            //object/complex types need to recursively call this method until the end of the tree is reached
            else
            {
                var complexType = GetPropertyValue(graph, propertyInfo.Name);
                Serialize(serializationStream, complexType);
            }
        }

        sw.Close();
    }
    #endregion


    public static object GetPropertyValue(object sourceObject, string propertyName)
    {
        if (sourceObject == null)
        {
            return null;
        }

        object obj = sourceObject;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)
            {
                return null;
            }

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart, BindingFlags.Public | BindingFlags.Instance);
                if (pi == null)
                {
                    return null;
                }

                obj = pi.GetValue(obj, null);
            }
            else
            {
                // propertyNamePart is a reference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                // get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[") + 1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart - 1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length - indexStart - 1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName, BindingFlags.Public | BindingFlags.Instance);
                if (pi == null)
                {
                    return null;
                }

                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as Array[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    IList collectionAsList = unknownCollection as IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }
}

コンソール アプリからテストを実行して、次のようにします。

            Employee employee = new Employee {Name = "Nando", Gender = Gender.Male, Roles = new List<Role> {new Role {Name = "CEO", Value = 1}}};

        EmployeeList employeeList = new EmployeeList();
        employeeList.Banana = "It's delicious!";
        employeeList.Employees.Add(employee);

        employeeList.Serialize();

プロパティの値を取得できBananaます (プロパティ名で申し訳ありません。腹を立てると、命名規則がおかしくなってしまいます)。それ以外は何もありません。

これはかなり「問題を解決する」という質問ですが、オブジェクトを完全に反映してそのプロパティの名前と値を処理できることを理解するためのソースが見つかりません。
そこで、熟練した開発者に助けを求めて、いくつかの情報源を教えてもらいました。:-) どうもありがとう、
ナンド

4

0 に答える 0