2

I am using a method to try and iterate through an object to get all of the object's properties, some of which are lists of objects.

This all works except for the part where I check for objects within the initial object's properties. If it finds a list of objects I want it to iterate through them.

Annoyingly, I'm getting null on my list of whatever type.

I'm now getting an error in VS because pt isn't instantiated, but it would be at run time.

Below is the if statement I'm using to try and catch whatever object/List is being parsed.

Am I going the right (roundabout) way or doing this or is this completely wrong?

Problematic Code - if statement null list:

public static string DeconstructLists<T>(T obj, string body)
        {
            Type type = obj.GetType();
            PropertyInfo[] properties = type.GetProperties();

            foreach (PropertyInfo property in properties)
            {
                if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || property.PropertyType == typeof(bool))
                    body += property.Name + " = " + property.GetValue(obj, null) + Environment.NewLine;

                else
                {
                    if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
                    {
                        //null list exception
                        var list = (IEnumerable)property.GetValue(obj, null);
                        foreach (var item in list)
                        {
                            DeconstructLists(item, body);
                        }

                        // stack overflow exception
                        //var props = property.PropertyType.GetGenericArguments()[0];

                        //foreach (var p in props.GetProperties())
                        //{
                        //    DeconstructLists(p, body);
                        //}
                    }
                }
            }
            return body;
        }

Post create method:

public ActionResult Create(Company cmp)
        {
            if (ModelState.IsValid)
            {
                db.companys.Add(cmp);
                db.SaveChanges();
                // send email
                SendEmail(cmp);
                return RedirectToAction("Thankyou", "Home", new { form="ASN" });
            }
            return View(cmp);
        }

Send email method:

public static void SendEmail(Company cm)
        {
            string _body = "";
            string _subject = "ASN Form Request";

            _body = DeconstructLists<Company>(cm, _body);

            using (SmtpClient msgClient = new SmtpClient())
            {
                msgClient.EnableSsl = false;
                msgClient.DeliveryMethod = SmtpDeliveryMethod.Network;
                msgClient.UseDefaultCredentials = false;
                msgClient.Credentials = new NetworkCredential
                    {                    
                        UserName = "",
                        Password = ""
                    };
                msgClient.Host = "";
                msgClient.Port = 0;

                using (MailMessage msg = new MailMessage())
                {
                    msg.To.Add(""); // to add
                    msg.From = new MailAddress("");// from add
                    msg.Subject = _subject;
                    msg.Body = _body;
                    // preparing the message to be sent
                    msgClient.Send(msg);
                }
            }
        }

Class objects:

public class Company
    {
        public int companyId { get; set; }
        public string name { get; set; }
        public string telephone { get; set; }
        public string regNumber { get; set; }
        public virtual IList<Asn> asns { get; set; }
        public virtual IList<Contact> contacts { get; set; }
    }
    public class Contact
    {
        public int contactId { get; set; }
        public int companyId { get; set; }
        public Company company { get; set; }
        public string name { get; set; }
        public string telephone { get; set; }
    }
public class Asn
    {
        public int asnId { get; set; }
        public int companyId { get; set; }
        public Company company { get; set; }
        public bool userBehalf { get; set; }
        public bool something { get; set; }
    }
PurpleSmurph
  • 2,055
  • 3
  • 32
  • 52
  • 2
    `(List)` ?! You cannot do that. – varocarbas Sep 14 '15 at 10:02
  • Yes I know but it was the best way to demonstrate what I'm trying to get, I want a list of whatever `property.PropertyType` is. Due to using generics I can't assign it as something and don't want an `if` or `switch` to check through the possible objects, I want to be able to parse anything to it and it'll iterate through the object's properties even if they're lists of objects. Apologies, hope I'm making sense. – PurpleSmurph Sep 14 '15 at 10:05
  • Perhaps something like this can help: http://stackoverflow.com/questions/612689/a-generic-list-of-anonymous-class – varocarbas Sep 14 '15 at 10:06
  • Thanks, shall take a look. – PurpleSmurph Sep 14 '15 at 10:09

2 Answers2

3

If it finds a list of objects I want it to iterate through them.

You don't need a list for iteration, the minimum iteratable type is IEnumerable. In fact your if statement is checking just that

if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
    // ...
}

So why not just using inside

var list = (IEnumerable)property.GetValue(obj, null);
foreach (var item in list)
{
    DeconstructLists(item, body);
}

EDIT: See this, it works, then see why yours does not:

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

namespace Tests
{
    class Test
    {
        static void Main(string[] args)
        {
            var company = new Company
            {
                companyId = 1,
                name = "ACME",
            };
            company.asns = new List<Asn>
            {
                new Asn { asnId = 1, companyId = company.companyId, company = company  },
                new Asn { asnId = 2, companyId = company.companyId, company = company  },
            };
            company.contacts = new List<Contact>
            {
                new Contact { contactId = 1, companyId = company.companyId, company = company, name = "Contact1" },
                new Contact { contactId = 2, companyId = company.companyId, company = company, name = "Contact2" }
            };
            var body = DeconstructLists(company, "");
        }
        public static string DeconstructLists<T>(T obj, string body)
        {
            var type = obj.GetType();
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int) || property.PropertyType == typeof(bool))
                    body += property.Name + " = " + property.GetValue(obj, null) + Environment.NewLine;
                else
                {
                    if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
                    {
                        body = body + property.Name + ": {" + Environment.NewLine;
                        var list = (IEnumerable)property.GetValue(obj, null);
                        foreach (var item in list)
                        {
                            body = body + item.GetType().Name + ": {" + DeconstructLists(item, "") + "}" + Environment.NewLine;
                        }
                        body = body + "}" + Environment.NewLine;
                    }
                }
            }
            return body;
        }
    }
    public class Company
    {
        public int companyId { get; set; }
        public string name { get; set; }
        public string telephone { get; set; }
        public string regNumber { get; set; }
        public virtual IList<Asn> asns { get; set; }
        public virtual IList<Contact> contacts { get; set; }
    }
    public class Contact
    {
        public int contactId { get; set; }
        public int companyId { get; set; }
        public Company company { get; set; }
        public string name { get; set; }
        public string telephone { get; set; }
    }
    public class Asn
    {
        public int asnId { get; set; }
        public int companyId { get; set; }
        public Company company { get; set; }
        public bool userBehalf { get; set; }
        public bool something { get; set; }
    }
}
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Yes that's what I initially tried to do, but that also results in `list` being `null` despite the `property` it's being assigned to being `List`. – PurpleSmurph Sep 14 '15 at 12:47
  • The your problem is somewhere else. Better post a code before this snippet, in order to see what is `obj`, what is `property` etc. – Ivan Stoev Sep 14 '15 at 13:42
  • Hmmm okay, it does display the correct property when stepping through but `var list` wouldn't be assigned to and always end up as `null`. I will post the model code and the other two methods. – PurpleSmurph Sep 14 '15 at 13:47
  • Forget about the "alternative", it's incorrect. When you put a breakpoint in a debugger inside your `SendEmail`function, are you sure `cm.asns` and `cm.contacts` are not really `null`? – Ivan Stoev Sep 14 '15 at 14:34
  • Yes, certain they're not null, they're saving to the database correctly. The alternative creates an infinite loop. – PurpleSmurph Sep 14 '15 at 14:35
  • This is unbelievable! Are you saying that if you use just `object list = property.GetValue(obj, null);`, you get `null', but at the same moment looking at the debugger, `obj.propertyName` is not null? – Ivan Stoev Sep 14 '15 at 14:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89599/discussion-between-purplesmurph-and-ivan-stoev). – PurpleSmurph Sep 14 '15 at 14:42
  • Fixed! Added small edit to guarantee no null gets through. Thank you! =) – PurpleSmurph Sep 14 '15 at 16:22
1

Maybe you could try something like this in your if statement ?

var genericType = property.PropertyType.GetGenericArguments()[0];
foreach (var prop in genericType.GetProperties())
{
    DeconstructLists(prop, body);
}

This topic may also help you: How to get the type of T from a member of a generic class or method?

Community
  • 1
  • 1