Return an anonymous collection from a method using Expando Object

Niladri.Biswas
Posted by in C# category on for Beginner level | Points: 250 | Views : 14048 red flag

In this article we will see how Expando Object class will help us to return an anonymous collection from a method.


 Download source code for Return an anonymous collection from a method using Expando Object

Introduction

At our regular work, we do return known datatypes from our methods and it is preety common.But how about returning a something whose data type is not known to us!.

For example, we are familiar with

private List GetStringCollection()
{
	// some meaningful code that will return a string collection
}

But how about

private List GetAnonymousCollection()
{
	var result = (from item in items
				  select new
				  {
				    Property1= item.value1,
					Property2= item.value2
				  }).ToList();
	return result; // what is the data type of   result? It is purely anonymous.

}

From the above code, the question that crops up is "what is the data type of result?" It is purely anonymous.People may argue that so what is the big deal.Here are the possible solutions

Solution1:Create a CONCRETE CLASS and type cast to it

Create a Class with those properties ,make a proper strongly type cast and return it. e.g.

class SomeConcreteClass
{
   public int Property1 { set; get; }
   public int Property2 { set; get; }
}

private List GetAnonymousCollection()
{
	var result = (from item in items
				  select new SomeConcreteClass
				  {
				    Property1= item.value1,
					Property2= item.value2
				  }).ToList();
	return result; 
}

Consider the case that we have been asked not to create a concreate class (say it's a business constraint).In that case this solution cannot be accepted. Also say many of such anonymous types are there and it is not feasible to create a concrete class for everything.Right!.So, this solution is not acceptable.

Solution2:Use DYNAMIC keyword

I believe that by this time everyone has come across the word "dynamic" (specially who are programming in dotnet4.0). If not please read this.

Let us see the implementation using the same.

 private dynamic GetAnonymousCollection()
{
	var result = (from item in items
				  select new SomeConcreteClass
				  {
				    Property1= item.value1,
					Property2= item.value2
				  }).ToList();
	return result; 
}

Perfect!But suppose we want to further do some kind of LINQ operation (that involves JOIN/WHERE clause) using the result set.It is quite difficult to go ahead and we may encounter with

Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed

Please read this article for more information.

Solution3:Use LIST

Let's see the implementation

private List<object> GetAnonymousCollection()
{
	var result = (from item in items
				  select new 
				  {
				    Property1= item.value1,
					Property2= item.value2
				  }).ToList();
	return result; 
}

Alright.But we cannot get the properties directly and will get

We can however do a nasty hack by using some loops but that is work around and not a feasible one.

The proposed solution:Use LIST<ExpandoObject>

We can however, achieve both the goals by using Expando Objects.For example

private LIST<ExpandoObject> GetAnonymousCollection()
{
	var result = items
				 .Select(item =>
				{
					dynamic expandoObj = new ExpandoObject();
					expandoObj.Property1 = item.value1;
					expandoObj.Property2 = item.value2;
					return (ExpandoObject)expandoObj;
				}).ToList<ExpandoObject>();
	return result; 
}

So what is an Expando Object?

It represents an object whose members can be dynamically added and removed at runtime.It is defined in the System.Core assembly and belongs to System.Dynamic namespace.

A detailed look inside the Expando Object reveals the following

The Expando Class cannot be inherited as it is Sealed. It implements six different interfaces. Out of which the below two needs special attention

IDynamicMetaObjectProvider

We know that any object that can have its operations bound at runtime must implement the IDynamicMetaObjectProvider. So is the Expando object.

Hence dynamic dyn = new ExpandoObject(); is a perfectly valid statement.

INotifyPropertyChanged

Whenever a new member is added or modified, the class raises the PropertyChange Event.

Let us now see how to return an anonymous collection from a method using Expando Object and then use it in LINQ query

Let us first fire up an windows application which will look as

Now let us prepare two xml files viz "Employee.xml" and "Department.xml" that will act as datasource.The file contents are as under

Employee.xml

Department.xml

Now let us write a method for reading the "Employee.xml" and store it in an Expando Object.

 private List<ExpandoObject> GetEmpInformation()
        {
            var directoryPath = Environment.CurrentDirectory.Replace("\\bin\\Debug", "\\DataSource");
            var filePath = Path.Combine(directoryPath, "Employee.xml");
            try
            {
                //Load xml
                XDocument xdoc = XDocument.Load(filePath);
                if (xdoc == null) return null;

                var empDetails = xdoc.Descendants("Employee")
                    .Select(empDetail =>
                    {
                        dynamic expandoObj = new ExpandoObject();

                        expandoObj.EmployeeId = Convert.ToInt32(empDetail.Attribute("Id").Value);
                        expandoObj.EmployeeName = empDetail.Attribute("Name").Value;
                        expandoObj.DepartmentCode = empDetail.Attribute("DepartmentCode").Value;
                        
                        return (ExpandoObject)expandoObj;

                    }).ToList();

                return empDetails;

            }
            catch (Exception ex)
            {
                throw ex;                
            }
        }

First we are creating a new System.Xml.Linq.XDocument from the xml file usng the "Load" method of "XDocument" class.Then we are returning a filtered collection of the descendant elements(which is "Employee" here) for this document in document order.We are doing so by using the "Descendants" method of "XContainer" class.This class represents a node that can contain other nodes.

We are using the "Select" method for projecting each element of a sequence into a new form.Inside that we are first creating an "ExpandoObject". And then we are creating the properties of that on the fly and assigning the values.Finally returning the same.

A similar kind of implementation follows for reading the "Department.xml"

private List<ExpandoObject> GetDeptInformation()
        {
            var directoryPath = Environment.CurrentDirectory.Replace("\\bin\\Debug", "\\DataSource");
            var filePath = Path.Combine(directoryPath, "Department.xml");
            try
            {
                //Load xml
                XDocument xdoc = XDocument.Load(filePath);
                if (xdoc == null) return null;

                var deptDetails = xdoc.Descendants("Department")
                    .Select(deptDetail =>
                    {
                        dynamic expandoObj = new ExpandoObject();

                        expandoObj.DepartmentCode = deptDetail.Attribute("DepartmentCode").Value;
                        expandoObj.DepartmentName = deptDetail.Attribute("Department").Value;

                        return (ExpandoObject)expandoObj;

                    }).ToList();

                return deptDetails;

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

So now we have both the Employee and Department informations (collections) at our hand.The last step is to fire a JOIN using LINQ to find out the matching record.

List<ExpandoObject> EmpInformation = GetEmpInformation();
List<ExpandoObject> DeptInformation = GetDeptInformation();

            //join between  EmpInformation and DeptInformation       
            var recordSet = (
                                                    from emp in EmpInformation
                                                    join dept in DeptInformation on
                                                    (string)((IDictionary<string, object>)emp)["DepartmentCode"] equals
                                                    (string)((IDictionary<string, object>)dept)["DepartmentCode"]                                                 

                                                      select new
                                                      {
                                                          EmployeeId = (int)((IDictionary<string, object>)emp)["EmployeeId"],
                                                          EmployeeName = (string)((IDictionary<string, object>)emp)["EmployeeName"],
                                                          DepartmentCode = (string)((IDictionary<string, object>)dept)["DepartmentCode"],
                                                          DepartmentName = (string)((IDictionary<string, object>)dept)["DepartmentName"]
              
                                                     }).ToList();

ExpandoObject implements IDictionary<string, object>> interface for maintaining its list of members.The rest is pure join condition of Linq.

The final result is as under

References

ExpandoObject Class

Conclusion

So in this article we have seen as how Expando Object class has helped to return an anonymous collection from a method.Hope this will be useful.Zipped code is attached herewith.Thanks for reading.

Page copy protected against web site content infringement by Copyscape

About the Author

Niladri.Biswas
Full Name: Niladri Biswas
Member Level: Platinum
Member Status: Member
Member Since: 10/25/2010 11:04:24 AM
Country: India
Best Regards, Niladri Biswas
http://www.dotnetfunda.com
Technical Lead at HCL Technologies

Login to vote for this post.

Comments or Responses

Posted by: Anup1252000 on: 5/10/2013 | Points: 25
Cool article on Expando object

Login to post response

Comment using Facebook(Author doesn't get notification)