The previous version of C# introduced anonymous types which were very useful for returning types without declaring them. One of the big problems of anonymous type is when returning them from a method. Although it is possible to return an anonymous type by casting it into another anonymous type the whole process is very trivial and ugly. C# 4.0 introduces dynamic types which provides the dynamic functionality into the C# language. You can consider the dynamic behavior of JavaScript and Ruby now available in the C# language and living inside visual studio. Let’s check out the following code which returns anonymous types from the method.
static void Main(string[] args)
{
var person = GetPerson();
var typedPerson = Cast(person, new { FirstName = "", LastName = "" });
Console.WriteLine(typedPerson.FirstName);
Console.WriteLine(typedPerson.LastName);
}
private static T Cast<T>(object obj, T type)
{
return (T)obj;
}
private static object GetPerson()
{
return new { FirstName = "Mohammad", LastName = "Azam" };
}
In the above code we have used the GetPerson method to return an anonymous type with two properties, FirstName and LastName. The cast method is used to cast an anonymous type to a different anonymous type which is returned to the main application.
Now check out the following code which uses the dynamic type to solve the same problem.
static void Main(string[] args)
{
dynamic person = GetPerson();
Console.WriteLine(person.FirstName);
Console.WriteLine(person.LastName);
}
As you can see the same result is achieved using less code.
One of the practical uses of dynamic types can be to use it as an DTO object to pass to the presentation layer. In the following the example I have created a customer DTO object and passed to the presentation layer for display.
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public List<Order> Orders { get; set; }
}
public static class ExtensionMethods
{
public static IEnumerable<dynamic> ToCustomerDTO(this List<Customer> list)
{
foreach (Customer customer in list)
{
yield return new
{
FirstName = customer.FirstName,
LastName = customer.LastName,
MiddleName = customer.MiddleName,
FirstOrder = customer.Orders[0].OrderName,
FullName = customer.FirstName + " " + customer.LastName
};
}
}
}
private void BindData()
{
gvCustomers.DataSource = _customerRepository.GetAll().ToCustomerDTO();
gvCustomers.DataBind();
}
The customer class contains several properties from which few of them will be returned as a customer DTO object. I have used ExtensionMethods ToCustomerDTO method which takes a list of customers as an input and returns an returns IEnumerable<dynamic>. Finally I have created an anonymous type inside the customer DTO function and returned it back to the client. The only downfall I see is that you have to create a DTO method for each individual class which will return to the presentation layer.
Finally the BindData method on the presentation layer uses the ToCustomerDTO method assign the customer DTO objects to the GridView datasource.
Check out the following ASPX code which is used to create of the GridView control on the the client side.
<asp:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<%# Eval("FirstName") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<%# Eval("LastName") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="First Order">
<ItemTemplate>
<%# Eval("FirstOrder") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Full Name">
<ItemTemplate>
<%# Eval("FullName") %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
UPDATE:
You can simply return IEnumerable instead of IEnumerable<dynamic> (Thanks Atif Aziz)
public static IEnumerable ToCustomerDTO(this List<Customer> list)
{
foreach (Customer customer in list)
{
yield return new
{
FirstName = customer.FirstName,
LastName = customer.LastName,
MiddleName = customer.MiddleName,
FirstOrder = customer.Orders[0].OrderName,
FullName = customer.FirstName + " " + customer.LastName
};
}
}