I found an interesting post on Deborah's Developer MindScape  (via Greg’s blog )and wanted to share a modification of the technique that can simplify the use of Office object models in C# and VB. I use this heavily in my VisioAutomation library.

 

First, let’s look at the the Deborah’s original solution :

var query = from d in Wd.Documents.Cast<Word.Document>()
            select d.Name;

SIMPLIFYING WITH EXTENSION METHODS

This works fine. Through the use of extension methods we can make this even more succinct. The core pain to address is the need to re-enter the type (“Word.Document”) when it is already clear that is the only possible kind of object in the collection

A simple extension method makes this even easier:

var query = from d in Wd.Documents.AsEnumerable()
            select d.Name;

The extension method that achieved this is trivial

public static class WordExtensions
{
    public static IEnumerable<Word.Document> AsEnumerable(this Word.Documents docs)
    {
        return docs.Cast<Word.Document>();
    }

}

SOURCE CODE

The full source code is below ( you can get the entire project from my SkyDrive)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Word = Mi2crosoft.Office.Interop.Word;

namespace DemoOfficeCollectionsIEnumerable
{
    class Program
    {

        static void Main(string[] args)
        {
            before();
            after_with_an_extension_method();

        }

        public static void before()
        {

            // Start Word and get Application object
            var Wd = new Word.Application();

            // Define documents
            var doc1 = Wd.Documents.AddEmptyDoc();
            var doc2 = Wd.Documents.AddEmptyDoc();

            // Use Linq to access the document names.
            var query = from d in Wd.Documents.Cast<Word.Document>()
                        select d.Name;
            var docsnames1 = query.ToList();

            // Or use Lambda expressions
            var query2 = Wd.Documents.Cast<Word.Document>().Select(d=> d.Name);
            var docnames2 = query2.ToList();

        }

        public static void after_with_an_extension_method()
        {
            // Add to the top of the code file

            object missingValue = System.Reflection.Missing.Value;

            // Start Word and get Application object
            var Wd = new Word.Application();

            // Define documents
            var doc1 = Wd.Documents.AddEmptyDoc();
            var doc2 = Wd.Documents.AddEmptyDoc();

            // Use Linq to access the document names.
           
var query = from d in Wd.Documents.AsEnumerable()
                        select d.Name;

            var docsnames1 = query.ToList();

            // Or use Lambda expressions
            var query2 = Wd.Documents.AsEnumerable().Select(d => d.Name);
            var docnames2 = query2.ToList();

        }

    }

    public static class WordExtensions
    {
        public static IEnumerable<Word.Document> AsEnumerable(this Word.Documents docs)
        {
            return docs.Cast<Word.Document>();
        }

        public static Word.Document AddEmptyDoc(this Word.Documents docs)
        {
            object missingValue = System.Reflection.Missing.Value;
            return docs.Add(ref missingValue, ref missingValue,
                                   ref missingValue, ref missingValue);
        }
    }

}

PARTING THOUGHTS

  • I through in an extra extension method (AddEmptyDoc) and liberal use of ‘var’ to make the sample source code smaller