递归获取属性和值&子属性和对象的值

时间:2013-10-27 12:39:21

标签: c# reflection

我有3个类,形成如下对象:

public class Pax
{
    public PaxType PaxType { get; set; }
    public int Age { get; set; }
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Room
    {
        public Room()
        {
            Paxes = new List<Pax>();
        }

        public List<Pax> Paxes { get; set; }
    }

public class AvaliableHotelRequest
{
    public AvaliableHotelRequest()
    {
        Rooms = new List<Room>();
    }

    public string Method { get; set; }
    public string ApiKey { get; set; }
    public string DestinationId { get; set; }
    public DateTime CheckIn { get; set; }
    public DateTime CheckOut { get; set; }
    public string Currency { get; set; }
    public string ClientNationality { get; set; }
    public bool OnRequest { get; set; }
    public List<Room> Rooms { get; set; }
}

我需要使用反射将以下对象输入到这样的字符串中:

        var pax1 = new Pax()
        {
            PaxType = PaxType.Adult
        };

        var pax2 = new Pax()
        {
            PaxType = PaxType.Adult
        };

        var pax3 = new Pax()
        {
            PaxType = PaxType.Children,
            Age = 5
        };

        var paxList1 = new List<Pax> {pax1, pax2, pax3};
        var paxList2 = new List<Pax> { pax2, pax3 };
        var rooms = new List<Room>(){new Room(){Paxes = paxList1}, new Room(){Paxes = paxList2}};


        var request = new AvaliableHotelRequest()
        {
            ApiKey = "jhjfjdshsfjkhjhfsdfks",
            CheckIn = DateTime.Now,
            CheckOut = DateTime.Now.AddDays(5),
            ClientNationality = "AU",
            Currency = "EUR",
            DestinationId = "LD6J",
            Method = "getAvailableHotel",
            OnRequest = false,
            Rooms = rooms
        };
  

输出:   ?方法= getAvailableHotel&安培; apiKey = kggdjjgdhgkjghkgjghkjdg&安培;目标-ID = LD6J&安培;签= 2011-04-20&安培;在checkOut = 2011-04-24&安培;货币= EUR&安培; clientNationality = UK&安培; onRequest =假安培;房间[0] [0] [paxType ] =成人及房间[0] [1] [paxType] =成人及房间[0] [2] [paxType] =儿童及安培;房间[0] [2] [年龄] = 6&安培;房间[1] [0] [paxType] =成人及房间[1] [1] [paxType] =成人及房间[1] [2] [paxType] =儿童及安培;房间[1] [2] [年龄] = 8

尝试了不同的方法,但无法通过这个问题。 如果你能帮助我,我将感激不尽。

我找到了Recursively Get Properties & Child Properties Of An Object 但它只是列出属性而不是值。 感谢。

2 个答案:

答案 0 :(得分:1)

另一种选择是定义自定义序列化机制。

例如,请考虑以下实现(具有一些粗糙边缘并且不必覆盖角落情况)。以下接口将某个对象的序列化定义为查询部分:

public interface IQueryPartDescriptor
{
    /// <summary>
    /// Converts the specified object into a string usable as query part.
    /// </summary>
    string ObjectToQueryPart(string prefix, object obj);

    /// <summary>
    /// Describes the properties containing lists of children objects.
    /// </summary>
    IEnumerable<ChildrenCollectionDescriptor> ChildrenListsDescriptors { get; }
}

使用子集合描述符,如:

public struct ChildrenCollectionDescriptor
{
    private readonly Func<object, IEnumerable<object>> _getChildren;
    private readonly Func<int, string, string> _buildChildPrefix;

    public ChildrenCollectionDescriptor(
        Func<object, IEnumerable<object>> getChildren,
        Func<int, string, string> buildChildPrefix)
        : this()
    {
        _getChildren = getChildren;
        _buildChildPrefix = buildChildPrefix;
    }

    public IEnumerable<object> GetChildren(object parent)
    {
        return _getChildren(parent);
    }

    public string BuildChildPrefix(int childPosition, string accumulatedPrefix)
    {
        return _buildChildPrefix(childPosition, accumulatedPrefix);
    }
}

您所描述的每个类的此接口的实现将类似于:

public class PaxDescriptor : IQueryPartDescriptor
{
    public string ObjectToQueryPart(string prefix, object obj)
    {
        var pax = (Pax)obj;
        var queryPart = prefix + "[paxType]=" + pax.PaxType;
        if (pax.PaxType == PaxType.Child)
        {
            queryPart += prefix + "[age]=" + pax.Age;
        }

        return queryPart;
    }

    public IEnumerable<ChildrenCollectionDescriptor> ChildrenListsDescriptors
    {
        get { return Enumerable.Empty<ChildrenCollectionDescriptor>(); }
    }
}

public class RoomDescriptor : IQueryPartDescriptor
{
    public string ObjectToQueryPart(string prefix, object obj)
    {
        return String.Empty;
    }

    public IEnumerable<ChildrenCollectionDescriptor> ChildrenListsDescriptors
    {
        get
        {
            return new[]
            {
                new ChildrenCollectionDescriptor(
                    room => ((Room)room).Paxes,
                    (index, roomsPrefix) => roomsPrefix + "[" + index + "]")
            };
        }
    }
}

public class AvaliableHotelRequestDescriptor : IQueryPartDescriptor
{
    public string ObjectToQueryPart(string prefix, object obj)
    {
        var request = (AvaliableHotelRequest)obj;
        return
            "method=" + request.Method + "&" +
            "apiKey=" + request.ApiKey + "&" +
            "destinationID=" + request.DestinationId + "&" +
            "checkIn=" + request.CheckIn.ToString("yyyy-MM-dd") + "&" +
            "checkOut=" + request.CheckOut.ToString("yyyy-MM-dd") + "&" +
            "currency=" + request.Currency + "&" +
            "clientNationality=" + request.ClientNationality + "&" +
            "onRequest=" + request.OnRequest.ToString().ToLower();
    }

    public IEnumerable<ChildrenCollectionDescriptor> ChildrenListsDescriptors
    {
        get
        {
            return new[]
            {
                new ChildrenCollectionDescriptor(
                    request => ((AvaliableHotelRequest)request).Rooms,
                    (index, _) => "&rooms[" + index + "]")
            };
        }
    }
}

当然,接口的实现可以由有问题的类本身提供。

现在,整个序列化部分将是:

public static string ToQuery(object root, IDictionary<Type, IQueryPartDescriptor> partDescriptors)
{
    var queryBuilder = new StringBuilder();
    AddQueryPart(root, String.Empty, partDescriptors, queryBuilder);

    return queryBuilder.Insert(0, '?').ToString();
}

private static void AddQueryPart(
    object obj,
    string prefixInQuery,
    IDictionary<Type, IQueryPartDescriptor> partDescriptors,
    StringBuilder queryBuilder)
{
    var queryPartDescriptor = partDescriptors[obj.GetType()];

    queryBuilder
        .Append(queryPartDescriptor.ObjectToQueryPart(prefixInQuery, obj));

    foreach (var childrenListDescriptor in queryPartDescriptor.ChildrenListsDescriptors)
    {
        var children = childrenListDescriptor.GetChildren(obj).ToList();
        for (var childIndex = 0; childIndex < children.Count; childIndex++)
        {
            var childPrefix = childrenListDescriptor.BuildChildPrefix(childIndex, prefixInQuery);
            AddQueryPart(children[childIndex], childPrefix, partDescriptors, queryBuilder);
        }
    }
}

这种方法不涉及反射,而且更加模块化。您还可以通过添加更多描述符来轻松扩展所涵盖类型的数量。

答案 1 :(得分:-1)

这是一个想法。 反射在这里?显示您可以应用反射的位置。 在这种情况下,您可以反映 Room Pax 的所有属性,并使用此信息设置参数,而不是对其进行硬编码。

List<string> parameters = new List<string>();

// reflection here?
parameters.Add("ApiKey=" + request.ApiKey);
// ... more request parameters here

for (int i = 0; i < request.Rooms.Count; i++)
{
    Room room = request.Rooms[i];

    for (int k = 0; room.Paxes.Count; k++)
    {
        Pax pax = room.Paxes[k];
        string roomParam = "room[" + i + "][" + k + "]";

        // reflection here?
        parameters.Add(roomParam + "[age]=" + pax.Age);
        // ... more pax parameters
    }
}

// we join all parameters get the query string
string query = "?" + String.Join("&", parameters)