簡體   English   中英

使用反射從復雜類中獲取值

[英]Get Values From Complex Class Using Reflection

我有一個類,它是從xml字符串創建和填充的,我為了示例目的簡化了它:

[XmlRoot("Person")]
public sealed class Person
{
    [XmlElement("Name")]
    public string Name { get; set; }

    [XmlElement("Location")]
    public string Location { get; set; }

    [XmlElement("Emails", Type = typeof(PersonEmails)]
    public PersonEmails Emails { get; set; }
}

public class PersonEmails
{
    [XmlElement("Email", Type = typeof(PersonEmail))]
    public PersonEmail[] Emails { get; set; }
}

public class PersonEmail
{
    [XmlAttribute("Type")]
    public string Type { get; set; }

    [XmlText]
    public string Value { get; set; }
}

為了提取信息,我試圖將它們加載到另一個類中,這簡單地說:

public class TransferObject
{
    public string Name { get; set; }

    public ObjectField[] Fields { get; set; }
}

public class ObjectField
{
    public string Name { get; set; }
    public string Value { get; set; }
}

我只是從另一個對象填充“Fields”,它只是(Name =“Location”,Value =“London”),但對於電子郵件,(Name =“Email”+ Type,Value = jeff @ here。 COM)

目前我可以填充其他所有領域,但我仍然堅持使用電子郵件,並且知道如何深入挖掘以便能夠使用反射(或不使用)來獲取我需要的信息。 目前我正在使用:

Person person = Person.FromXmlString(xmlString);
List<ObjectField> fields = new List<ObjectField>();
foreach (PropertyInfo pinfo in person.getType().GetProperties()
{
    fields.Add(new ObjectField { Name = pinfo.Name, Value = pinfo.getValue(person, null).ToString();
}

如何擴展上述內容以將我的所有電子郵件添加到列表中?

您正在嘗試將復雜值類型轉換為字符串值,以便丟失數據。 而是使用以下代碼:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        person.Name = "Person One";
        person.Location = "India";
        person.Emails = new PersonEmails();
        person.Phones = new PersonPhones();
        person.Emails.Emails = new PersonEmail[] { new PersonEmail() { Type = "Official", Value = "xyz@official.com" }, new PersonEmail() { Type = "Personal", Value = "xyz@personal.com" } };
        person.Phones.Phones = new PersonPhone[] { new PersonPhone() { Type = "Official", Value = "789-456-1230" }, new PersonPhone() { Type = "Personal", Value = "123-456-7890" } };

        List<ObjectField> fields = new List<ObjectField>();

        fields = GetPropertyValues(person);

    }

    static List<ObjectField> GetPropertyValues(object obj)
    {
        List<ObjectField> propList = new List<ObjectField>();

        foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
        {
            var value = pinfo.GetValue(obj, null);

            if (pinfo.PropertyType.IsArray)
            {
                var arr = value as object[];
                for (var i = 0; i < arr.Length; i++)
                {
                    if (arr[i].GetType().IsPrimitive)
                    {
                        propList.Add(new ObjectField() { Name = pinfo.Name + i.ToString(), Value = arr[i].ToString() });
                    }
                    else
                    {
                        var lst = GetPropertyValues(arr[i]);
                        if (lst != null && lst.Count > 0)
                            propList.AddRange(lst);
                    }
                }
            }
            else
            {
                if (pinfo.PropertyType.IsPrimitive || value.GetType() == typeof(string))
                {
                    propList.Add(new ObjectField() { Name = pinfo.Name, Value = value.ToString() });
                }
                else
                {
                    var lst = GetPropertyValues(value);
                    if (lst != null && lst.Count > 0)
                        propList.AddRange(lst);
                }
            }
        }
        return propList;
    }
}

檢查此代碼段:

if(pinfo.PropertyType.IsArray)
{
  // Grab the actual instance of the array.
  // We'll have to use it in a few spots.
  var array = pinfo.GetValue(personObject);

  // Get the length of the array and build an indexArray.
  int length = (int)pinfo.PropertyType.GetProperty("Length").GetValue(array);

  // Get the "GetValue" method so we can extact the array values
  var getValue = findGetValue(pinfo.PropertyType);

  // Cycle through each index and use our "getValue" to fetch the value from the array.
  for(int i=0; i<length; i++)
    fields.Add(new ObjectField { Name = pinfo.Name, Value = getValue.Invoke(array, new object[]{i}).ToString();
}

// Looks for the "GetValue(int index)" MethodInfo.
private static System.Reflection.MethodInfo findGetValue(Type t)
{
  return (from mi in t.GetMethods()
    where mi.Name == "GetValue"
    let parms = mi.GetParameters()
    where parms.Length == 1
    from p in parms
    where p.ParameterType == typeof(int)
    select mi).First();
}

您可以使用Reflection它...您可以利用Type可以告訴您它是否是數組( IsArray )的事實...然后利用Array具有方法GetValue(int index)的事實GetValue(int index)將返回給你一個值。

根據你的評論

因為Emails是不同類中的屬性,所以應該使用遞歸。 然而,訣竅是知道何時進入下一個級別。 真的,這取決於你,但如果是我,我會使用某種Attribute

static void fetchProperties(Object instance, List<ObjectField> fields)
{
  foreach(var pinfo in instance.GetType().GetProperties())
  {
    if(pinfo.PropertyType.IsArray)
    {
      ... // Code described above
    }
    else if(pinfo.PropertyType.GetCustomAttributes(typeof(SomeAttribute), false).Any())
      // Go the next level
      fetchProperties(pinfo.GetValue(instance), fields);
    else
    {
      ... // Do normal code
    }

  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM