4

I'm relatively new to C# and Office automation and recently I found myself trying to obtain a reference to someone's Outlook inbox and sorting the emails by Received time. It wasn't working until I found a solution elsewhere on the web where the Inbox is assigned to a local variable of type Microsoft.Office.Interop.Outlook.Items and then the sort is performed on the local variable and it works. The question, however, is why? I thought that in C# objects are references and when you declare a new Outlook.Inbox reference and then assign it the Items from the user's Inbox, it simply serves as an additional pointer to the actual emails, and DOES NOT actually copy each of the emails to a new collection. So it should be no different than calling Sort on the original reference, right? Obviously I'm wrong, so I'd appreciate an explanation. Thanx!!

using Outlook = Microsoft.Office.Interop.Outlook;    
...
Outlook.Folder oInbox = (Outlook.Folder)oApp.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);

oInbox.Items.Sort("[Received]", true); //this doesn't produce expected results
Outlook.Items inboxFolder = (Outlook.Items)oInbox.Items;
inboxFolder.Sort("[Received]", true);  //this DOES sort the items!
public wireless
  • 767
  • 8
  • 20
  • What is the type of oInbox.Items? It could be that type overrides the Sort method to have a different behavior. By casting to Outlook.Items you are getting the behavior from the base class. – cadrell0 Feb 09 '12 at 16:24

2 Answers2

6

You're performing a cast (by doing (Outlook.Items)oInbox.Items). Casting means that you're referring to an object of type X as type Y. This is valid in the following scenarios:

  • X is within the inheritance hierarchy of Y (meaning that it's either a parent class of Y or a child class of Y). In the case where X is a parent class, the cast will only succeed at runtime if the object in question actually is Y (or a type derived from Y)
  • Y is an interface type that is implemented by X
  • There is an explicit conversion defined from X to Y

Because of polymorphism, casting in the first case usually doesn't change the behavior of functions (though it can if the more derived type explicitly hides the implementation of the parent). My suspicion, however, is that this is your scenario; the type of oInbox.Items is a type that inherits from Outlook.Items but hides the implementation of Outlook.Items.Sort. By explicitly casting to the parent type, you're bypassing the new child implementation. Note that this sort of technique only works when the child hides the function rather than overriding a virtual function).

The second case can change behavior if X explicitly implements the function(s) on Y that you're intending to use. By casting to the interface, you're explicitly telling the compiler that you want it to bind your method call to the implementation for the interface rather than the ordinary public-facing method on the class itself.

The third almost always changes behavior, since you're getting a different type (and thus an entirely different object) altogether.

I can't speak as to which one of these cases yours falls into, since I don't have much experience with Office interop specifically, but this should answer your basic question of "how can these be different?"

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • Thanks for the explanation. I removed the cast operation and now have: (Outlook.Items inboxFolder = oInbox.Items;) It compiles and runs just fine, and when I call Sort on oInbox.Items it still fails to sort and when I call sort on inboxFolder it indeed sorts correctly. This is very odd and I never would have thought to create an additional reference for sorting had I not found the answer on Google – public wireless Feb 09 '12 at 16:57
  • @MikeItsMe: In that case, `Outlook.Items` is either an interface that is implemented by the type of `oInbox.Items`, a parent class of that type, or a type for which there's an *implicit* conversion available. You're right, though, in that it is certainly unintuitive and seems like a poor design choice. – Adam Robinson Feb 09 '12 at 17:10
  • I noticed that the Items property is listed as read only. That would explain why I can't sort them. But in C# is it possible to circumvent read only by assigning the underlying data to a new reference? Or maybe .Items property is doing a clone behind the scenes? Thanks for continuing the discussion! – public wireless Feb 09 '12 at 17:24
  • Read only in that context simply means that you cannot modify the *value of the property*. It doesn't affect your ability to perform operations on the value itself. – Adam Robinson Feb 09 '12 at 17:35
2

You are not creating a new Outlook.Inbox- you are creating a new reference to the existing inbox. Thus the sorting is actually done in place on the existing inbox.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • Exactly. But why does the Sort work on the new reference but not on the original reference? I could understand if the original Inbox was read only, and one needed to copy all the items to a new collection in order to modify, but like you stated, the Sort is being performed on the existing inbox. – public wireless Feb 09 '12 at 16:28
  • Ah, missed that. See @AdamRobinson's answer. – Chris Shain Feb 09 '12 at 16:30