• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1457
  • Last Modified:

C# - Reflection - How to get attribute "DataContract" for child objects

I have a class as followed:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

/// <summary>
/// Summary description for Class1
/// </summary>
public static class Class1
{
	

    public class ParentObject
    {
        public int pp1 { get; set; }
        public int pp2 { get; set; }
        public ChildObject child1 { get; set; }
    }

    [DataContract]
    public class ChildObject
    {
        public int cp1 { get; set; }
        public int cp2 { get; set; }
    }
}

Open in new window


I want to use reflection to go through all properties of ParentObject and determine which property has attribute "DataContract" (in this case, the answer is property of type ChildObject. But I need the code to determine this answer dynamically).

For instance, I know I can get list of properties in ParentObject by using the following code:
Type parent = typeof(Class1.ParentObject);
        System.Reflection.PropertyInfo[] properties = parent.GetProperties();

Open in new window


But how do I find out which property has attribute "DataContract"?
0
fippif
Asked:
fippif
  • 3
  • 2
1 Solution
 
Jaime OlivaresSoftware ArchitectCommented:
This can be achieved in one line with Linq extension methods:

            PropertyInfo dataprop = parent.GetProperties().FirstOrDefault(p => p.GetCustomAttributes(typeof(DataContractAttribute), false).Length > 0);

you will need to declare the System.Linq namespace at the top of your file.
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
fippifAuthor Commented:
None of these responses resolved my issue. It seems the provided samples look at all the attributes for properties in ParentObject class. For instance, I added "Required" attributed to child1 property in class ParentObject:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;

/// <summary>
/// Summary description for Class1
/// </summary>
public static class Class1
{
	

    public class ParentObject
    {
        public int pp1 { get; set; }
        public int pp2 { get; set; }

        [Required] // new attribute
        public ChildObject child1 { get; set; }
    }

    [DataContract]
    public class ChildObject
    {
        public int cp1 { get; set; }
        public int cp2 { get; set; }
    }
}

Open in new window


And I modified my code as followed (please note the return results):

 Class1.ParentObject p = new Class1.ParentObject() { pp1 = 1, pp2 = 2, child1 = new Class1.ChildObject() };

        Type pType = p.GetType();

        bool b = pType.GetCustomAttributes(typeof(DataContractAttribute), true).Any(); // returns false
        PropertyInfo dataprop = pType.GetProperties().FirstOrDefault(prop => prop.GetCustomAttributes(typeof(DataContractAttribute), false).Length > 0); // returns null


        var props = pType.GetProperties();

        foreach (PropertyInfo itemProperty in props)
        {
            bool bc = itemProperty.GetCustomAttributes(typeof(DataContractAttribute), true).Any(); // returns false for all properties

            bool bc1 = itemProperty.GetCustomAttributes(typeof(RequiredAttribute), true).Any(); // returns true for property child1
        }

Open in new window


It seems the Required attribute for child1 object is recognized by the sample codes you provided. But the DataContractAttribute is NOT recognized for ChildObject type. Do you see a problem with my code? Am I doing something wrong?
Thx.
0
 
fippifAuthor Commented:
In case this response helps others, it appears I needed PropertyType property of itemProperty. So, for the following class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;

namespace CustomAttributeTest
{
    public class Class1
    {
    }

    [DataContract]
    public enum Enum1
    {
        [EnumMember]
        item1,

        [EnumMember]
        item2
    }

    [DataContract]
    public class GrandChildClass
    {
        [Required(ErrorMessage = "prop1 of GrandChildClass is required")]
        public int? prop1 { get; set; }

        [Required(ErrorMessage = "prop2 of GrandChildClass is required")]
        public Enum1? prop2 { get; set; }
    }
    
    
    [DataContract]
    public class ChildClass
    {
        [Required(ErrorMessage = "prop1 of ChildClass is required")]
        public int? prop1 { get; set; }

        [Required(ErrorMessage = "prop2 of ChildClass is required")]
        public GrandChildClass prop2 { get; set; }
    }

    [DataContract]
    public class ParentClass
    {
        public int prop1 { get; set; }

        [Required(ErrorMessage = "prop2 of ParentClass is required")]
        public ChildClass prop2 { get; set; }
    }


}

Open in new window


I added the following method:

private static void ProcessTypes(object entity, List<object> lstEntity)
        {
            if (entity == null)
            {
                continueLoop = false;
            }

            while (continueLoop)
            {
                // Add entity to the list
                lstEntity.Add(entity);

                Type pType;
                // Get the type
                pType = entity.GetType();

                // Get all subtypes

                List<PropertyInfo> lstPropertyInfo = pType.GetProperties().Where(r => r.PropertyType.GetCustomAttributes(typeof(DataContractAttribute), true)
                            .Any())
                            .ToList();

                if (lstPropertyInfo.Count > 0)
                {
                    foreach (PropertyInfo itemProperty in lstPropertyInfo)
                    {
                        object newEntity = itemProperty.GetValue(entity, null);
                        ProcessTypes(newEntity, lstEntity);
                    }
                }
                else
                {
                    continueLoop = false;
                }

            }
            
        }

Open in new window


And called this method as followed:

List<object> lstEntity = new List<object>();

            GrandChildClass gcc = new GrandChildClass() { prop1 = 1, prop2 = Enum1.item1 };

            ProcessTypes(gcc, lstEntity);

Open in new window

0
 
fippifAuthor Commented:
The comments provided by experts did not refer to the detailed problem I had. Instead, those comments provided links to answers I had found online already. Furthermore, when I added more details to my question, none of the experts responded back. Unfortunately, the experts did not effectively help me with my question.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now