:::: MENU ::::

Tuesday, July 22, 2008

I was reading this particular entry from AlexJ's blog, in which he discussed how to use anonymous type returned from one function in another function.  I strongly recommend you read it first before reading any further.

Basically, most people would think that there is no easy way to return a strongly typed anonymous type from a function since you wouldn't know what it is that you are returning beforehand. Thus, if you wish to return an anonymous type from a function, you are forced to return it as object like so:

   1:          object CreateAnonymousObject()
   2:          {
   3:              return new { Name = "John Doe" };
   4:          }

The problem of doing it like this is that you lost the ability to access the Name property since object does not have a Name property.  So, your option is to cast it back to its original anonymous type, but alas, how could you do it?

It turned out that there is a way to do this using generic.  If you create a generic function that will return a generic type T and also pass an object of type T in the parameter, you can cast whatever object that you pass as T.  In effect, you are using the object of type T as your example to cast the boxed object to.  See the following code:

   1:  T CastByExample<T>(object source, T example)
   2:  {
   3:      return (T)source;
   4:  }

So now, you can do something like this (for the sake of clarity, I am not going to shorthand these examples):

   1:  var o = CreateAnonymousObject();
   2:  var prototype = new { Name = "" };
   3:  var result = CastByExample(o, prototype);
   4:  Console.WriteLine(result.Name); //This should work just fine

To make things a little bit easier to read, we can use the new extension method feature of .NET 3.5 like so:

   1:  public static class MyExtensions
   2:  {
   3:      public static T CastToTypeOf<T>(this object source, T example)
   4:      {
   5:          return (T)source;
   6:      }
   7:  }

And rewrite the example to:

   1:  var o = CreateAnonymousObject();
   2:  var prototype = new { Name = "" };
   3:  var result = o.CastToTypeOf(prototype);
   4:  Console.WriteLine(result.Name); //This should work just fine.

This is great.  I don't know what I am going to use it for, but it's nice to know that I can do it when I need it.

And then, another idea comes to my mind.  Hey, what if we need to do similar thing to an anonymous object collection.  How could I do that? How could one creata a generic list of anonymous object?  As it turned out, Kirill Osenkov already solve this particular problem.  You can see it here.

So, let's come up with something interesting to explore this problem.  Lets say that you are querying a Contact database through LINQ, but instead of returning the entire Contact fields, you wish to only return some of them.

Making thing simpler, I decided to mock the Contact class like so (too lazy to create a dbml, so I am querying from in-memory object :) ):

   1:  public class Contact
   2:  {
   3:      public string FirstName { get ; set; }
   4:      public string LastName { get; set; }
   5:      public string PhoneNumber { get; set; }
   6:      public string StreetAddress { get; set }
   7:      public string City { get; set; }
   8:  }

And here is an example function that will return you a list of Contacts:

   1:  IEnumerable<Contact> GetContacts()
   2:  {
   3:      return new List<Contact> {
   4:          new Contact { FirstName = "John", LastName = "Doe", PhoneNumber = "555-5501", StreetAddress = "123 Lala Lane", "Los Angeles" },
   5:          new Contact { FirstName = "Jane", LastName = "Doe", PhoneNumber = "555-5502", StreetAddress = "567 Lala Lane", "New York" }
   6:      };
   7:  }

And you only wish to return the FirstName and LastName from your LINQ query like so:

   1:  var query = from c in GetContacts()
   2:              select new { Name = c.FirstName + " " + c.LastName };

Again, for whatever reason, you really really want to encapsulate this as a method, so, you do something like this:

   1:  object GetContactNamesFrom(IEnumerable<Contact> contacts)
   2:  {
   3:      var query = from c in contacts
   4:                          select new { Name = c.FirstName +  " " + c.LastName };
   5:      return query.AsEnumerable();
   6:  }

Great!  Now you have something that can return a generic collection of an anonymous type.  But how can we use this in our own function and allow our function to access the Name property?

Well, combining what we've learnt so far, we can come up with something like this...

First, we know we can now cast something to an anonymous type (sort of) using the generic method CastByExample or CastToTypeOf as seen above.

Second, we need a way to create an anonymous collection.

Let's start with the second one first.  We need a way to create an anonymous collection.  So let's think about this a bit.  i hope you've read the blog post by Kirill by now.  If not, well, here is how you do it...

   1:  IEnumerable<T> CreateEnumerablesByExample<T>(T example)
   2:  {
   3:      return new List<T>();
   4:  }

Now you can do something like:

   1:  var prototype = new { Name = "" };
   2:  var prototypeCollection = CreateEnumerablesByExample(prototype); //This is now a generic collection of anonymous.

What's left for us to do is cast our LINQ result back as the prototypeCollection so we can get access to the Name property from our code like so:

   1:  var contactInfo = GetContactNamesFrom(GetContact());
   2:  var prototype = new { Name = "" };
   3:  var prototypeCollection = CreateEnumerablesByExample(prototype);
   4:  var result = contactInfo.CastToTypeOf(prototypeCollection);
   5:   
   6:  foreach(var c in result)
   7:  {
   8:      Console.WriteLine(c.Name);
   9:  };

We can do one better by using extension method.  Let's refactor CreateEnumerableFrom as an extension method like so:

   1:  public static IEnumerable<T> CreateEnumerablesOfThis<T>(this T prototype)
   2:  {
   3:      return new List<T>();
   4:  }
 

The refactored code of our final example will look like this:

   1:  var contactInfo = GetContactNamesFrom(GetContact());
   2:  var prototype = new { Name = "" };
   3:  var protoypeCollection = prototype.CreateEnumerablesOfThis();
   4:  var result = contactInfo.CastToTypeOf(prototypeCollection);
   5:   
   6:  foreach(var c in result)
   7:  {
   8:      Console.WriteLine(c.Name);
   9:  }

So, why would go through all these trouble?  Honestly, I have no idea.  I am just exercising my brain just to see if I can do such a thing.  I have no real need for this type of things yet.  Who knows... maybe someday...

More

Categories: