Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Looping through contacts or other items using Outlook Object Model and C++ is faster than using C#. The primary reason being the "Interop" layer and the marshalling of data that takes place when we use C# with Outlook Object Model.
In this case I was looping through 10,000 contacts and it took me just 20-25 seconds in C++ and almost 2 minutes in C#. The challenge was to improve the performance. Here is how I did it.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection; // to use Missing.Value
using System.IO;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace ReadContact
{
public class Program
{
public static void Main(string[] args)
{
//Holds the start time
DateTime start;
//Holds the end time
DateTime end;
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Get the NameSpace information.
Outlook.NameSpace oNS = oApp.GetNamespace("MAPI");
// Log on by using a dialog box to choose the profile.
oNS.Logon(Missing.Value, Missing.Value, true, true);
// Get the contacts folder
Outlook.MAPIFolder myContacts = oNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
// Get the items in the contact folder
Outlook.Items myContactItems = myContacts.Items;
// Record the start time
start = System.DateTime.Now;
// use SetColumns - This greatly improves performance
myContactItems.SetColumns("CompanyName,FirstName,LastName,Email1Address,IMAddress,BusinessTelephoneNumber, HomeTelephoneNumber,MobileTelephoneNumber");
// Use the foreach loop and get each item as an object instead of Microsoft.Office.Interop.Outlook.ContactItem
foreach (object item in myContactItems)
{
//Use reflection to get the desired properties
string FirstName = (string)GetProperty(item, "FirstName");
string LastName = (string)GetProperty(item, "LastName");
string HomeTelephoneNumber = (string)GetProperty(item, "HomeTelephoneNumber");
string IMAddress = (string)GetProperty(item, "IMAddress");
string BusinessTelephoneNumber = (string)GetProperty(item, "BusinessTelephoneNumber");
string MobileTelephoneNumber = (string)GetProperty(item, "MobileTelephoneNumber");
string CompanyName = (string)GetProperty(item, "CompanyName");
string Email1Address = (string)GetProperty(item, "Email1Address");
Console.WriteLine("First Name:" + " " + FirstName);
Console.WriteLine("Last Name:" + " " + LastName);
Console.WriteLine("Home Telephone Number:" + " " + HomeTelephoneNumber);
Console.WriteLine("IM Address:" + " " + IMAddress);
Console.WriteLine("Business Telephone Number:" + " " + BusinessTelephoneNumber);
Console.WriteLine("Mobile Telephone Number:" + " " + MobileTelephoneNumber);
Console.WriteLine("Company Name:" + " " + CompanyName);
Console.WriteLine("Email Address:" + " " + Email1Address);
}
//Record the end time
end = System.DateTime.Now;
//Get the difference
System.TimeSpan result2 = end.Subtract(start);
//Print the time taken
Console.WriteLine(String.Format("With SetColumns this took {0} ticks.", result2.Ticks));
Console.WriteLine(start.ToString());
Console.WriteLine(end.ToString());
// Log off.
oNS.Logoff();
//Clean up
oNS = null;
myContacts = null;
myContactItems = null;
oApp = null;
}
private static object GetProperty(object targetObject,string propertyName)
{
return targetObject.GetType().InvokeMember(propertyName,
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.GetProperty,
null,
targetObject,
null,
System.Globalization.CultureInfo.CurrentCulture);
}
}
}
Although I was not able to get the exact performance that I got using C++ but results were a lot better - from 2 minutes to 55-60 seconds.
Comments
- Anonymous
August 26, 2008
You can greatly improve performance by caching a MethodInfo object during the reflection part. I believe that it will save the reflection engine the time it takes to "locate" the requested member....