Tuesday, May 13, 2008

Accessing anonymous types from a different assembly

Anonymous types are one of the new features introduced in C# 3.0 which helps you to encapsulate a set of properties into an object without having to define a type. The type will not be available at the source code level (This is generated by the compiler).

In this article I will explain how to access anonymous types exposed from another assembly in the caller method. There are some very nice articles on the topic by Tom and Clark .

I have a GetContactList method which returns an anonymous type collection that is a result of the LINQ query.

public class Contact

{

public Int32 ContactID { get; set; }

public String ContactName { get; set; }

public Int32 CompanyID { get; set; }

}

public class Company

{

public Int32 CompanyID { get; set; }

public String CompanyName { get; set; }

public String CompanyURL { get; set; }

}

public Object[] GetContactList()

{

var contacts = from contact in GetContacts()

join company in GetCompanies()

on contact.CompanyID equals company.CompanyID

select new { contact.ContactName, company.CompanyName, company.CompanyURL };

return contacts.ToArray();

}

The properties of this return type cannot be accessed before casting it to an object.

The type returned from the above method looks something like this to the external caller.

<>f__AnonymousType0`3[System.String,System.String,System.String] b__3(BusinessCoreLayer.Contact, BusinessCoreLayer.Company)

I will go through some interesting parts of the above type

  • The 0 after the <>f__AnonymousType is a zero based index of each anonymous type definition. (If you have another anonymous type in the code that will have the index 1)
  • The 3 after the 0 represents the number of properties in the anonymous type (We have 3 properties – ContactName, CompanyName, CompanyURL)
  • The rest of the portions represent the data types and method name

I have created an Entity converter that will convert this anonymous type to the respective type in the caller function. The below given code will convert the anonymous type collection returned to the ContactDetails object.

public class ContactDetails

{

public String ContactName { get; set; }

public String CompanyName { get; set; }

public String CompanyURL { get; set; }

}

private ContactDetails EntityTranslator(Collection<KeyValuePair<String, Object>> propertyCollection)

{

ContactDetails cd = new ContactDetails();

foreach (KeyValuePair<String, Object> propertyInfo in propertyCollection)

{

switch (propertyInfo.Key)

{

case "ContactName":

cd.ContactName = propertyInfo.Value.ToString();

break;

case "CompanyName":

cd.CompanyName = propertyInfo.Value.ToString();

break;

case "CompanyURL":

cd.CompanyURL = propertyInfo.Value.ToString();

break;

}

}

return cd;

}

Now in the caller method I have to call the EntityTranslator like

Object[] contacts = Assembly2.GetContactList();

Collection<ContactDetails> details = new Collection<ContactDetails>();

foreach (Object contact in contacts)

{

ContactDetails cd = new ContactDetails();

Type t = contact.GetType();

PropertyInfo[] pInfo = t.GetProperties();

Collection<KeyValuePair<String, Object>> propertyCollection = new Collection<KeyValuePair<String, Object>>();

foreach(PropertyInfo pi in pInfo)

{

propertyCollection.Add(new KeyValuePair<String, Object>(pi.Name, pi.GetValue(contact, null)));

}

cd = ContactTranslator(propertyCollection);

details.Add(cd);

}

As you have seen by using Reflection we can access the properties of anonymous type returned from another assembly.

No comments: