0

XElementをトラバースしながら、プロパティを取得して値を設定するためにリフレクションを使用するメソッドを作成しようとしています。

解析するXML値のみを提供する次のようなクラスがあるとします。

class XMLController
{
    public string XML
    {
        get{
            return @"<FieldGroup name='People' count='20'>
                <Fields>
                    <Field Name='Jon' LastName='McFly'/>
                    <Field Name='Michael' LastName='Jackson'/>
                </Fields>
            </FieldGroup>";
        }
    }
}

そして、これは私のオブジェクトがどのように見えるかです:

class FieldGroup
{
    public string Name {get;set;}
    public string Count {get;set;}
    public IEnumerable<Field> Fields {get;set;}
}

class Field
{
    public string Name {get;set;}
    public string LastName {get;set;}
}

マッパーメソッドはトラバースXElementし、ノード名はオブジェクトと名前が一致しているので、これはもう少し役立つと思いますが、本当に役立つものは思いつきませんでした。型を渡したくありませんが、メソッドは同じ形式で渡されたほぼすべてのXMLで機能します。

XMLノードと属性が一致する名前であるという事実をすべて知っています。

これは私がやったことですが、実際には機能しませんでした。

class XMLObjectMapper
{
    public T Map<T>(XElement element) where T: class, new()
    {
        T entity = (T) Activator.CreateInstance(typeof(T));
        if(element.HasAttributes)
        {
            MapXMLAttributesToObject<T>(element,entity);
        }
        if(element.HasElements)
        {
            foreach (var childElement in element.Elements())
            {
                //if the child element has child elements as well, we know this is a collection.
                if(childElement.HasElements)
                {
                    var property = GetProperty<T>(childElement.Name.LocalName);
                    property.SetValue(entity,new List<property.PropertyType>());
                    Map<T>(childElement);

                }
                else
                {
                    var property = GetProperty<T>(childElement.Name.LocalName);
                    var type = Activator.CreateInstance(property.PropertyType);
                    type.Dump();
                }
            }
        }
        return entity;
    }

    private void MapXMLAttributesToObject<T>(XElement element, T entity)
    {
        foreach(XAttribute attribute in element.Attributes())
        {
            var property = GetProperty<T>(attribute.Name.LocalName);
            property.SetValue(entity,attribute.Value);
        }
    }

    private PropertyInfo GetProperty<T>(string propertyName)
    {
        return typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
    }
}
4

1 に答える 1

3

あなたは正しい方向に進んでいますが、お気づきのように、いくつかのエラーがあります。

property.PropertyType次のコードは、型名の代わりに値()を使用できないため、コンパイルされません。C#は静的に型付けされた言語であるため、型は変数ではなくコンパイル時に認識される必要があります。

new List<property.PropertyType>()

ただし、リフレクションを使用する場合は、実行時にタイプを選択できます。代わりにこれを行うことができます:

Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType))

あなたが持っている他の問題は、あなたがただ呼び出すことができないということですMap<T>(childElement)。まず第一に、Tは正しいタイプではありません。これは親要素のタイプであり、子のタイプではありません。第二に、子は実際にはコレクションであり、コレクションのMap<T>処理方法を知らず、個々のオブジェクトのみを扱います。子要素をループし、各要素にマップして(Map<T>コレクション内の要素のタイプを呼び出します-この例ではMap<Field)、それらすべてをコレクションに追加する必要があります。私はあなたの新しいバージョンを作りましたMap<T>

public T Map<T>(XElement element) where T : class, new()
{
    T entity = (T)Activator.CreateInstance(typeof(T));
    if (element.HasAttributes)
    {
        MapXMLAttributesToObject<T>(element, entity);
    }
    if (element.HasElements)
    {
        foreach (var childElement in element.Elements())
        {
            var property = GetProperty<T>(childElement.Name.LocalName);
            // If the child element has child elements as well, we know this is a collection.
            if (childElement.HasElements)
            {
                // Assume collections are of type IEnumerable<T> or List<T>
                var collectionElementType = property.PropertyType.GetGenericArguments()[0];
                // var collectionValue = new List<collectionElementType>()
                var collectionValue = Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType));
                foreach (var grandchildElement in childElement.Elements())
                {
                    // var collectionElement = this.Map<collectionElementType>(grandchildElement);
                    var collectionElement = this.GetType().GetMethod("Map").MakeGenericMethod(collectionElementType).Invoke(this, new object[] { grandchildElement });
                    collectionValue.GetType().GetMethod("Add").Invoke(collectionValue, new object[] { collectionElement });
                }
                property.SetValue(entity, collectionValue, null);
            }
            else
            {
                // I'm not sure what this should do -- this case doesn't happen in your example.
                throw new NotImplementedException();
            }
        }
    }
    return entity;
}

それは確かにもう少しエラー処理を必要とします、そして私が投げた場合にあなたが何か役に立つことをしたいと思ったと思いますNotImplementedException。ただし、サンプルでは機能します。

于 2013-03-19T05:58:07.687 に答える