Improved COM Interoperability in .NET 4.0

Improved COM Interoperability Introduction

Welcome to this installment of the .NET Nuts & Bolts column. The prior article focused on the future direction of managed languages and introduced trends that are influencing the future of C# and Visual Basic. It introduced the Dynamic Language Runtime (DLR) and touched ever so briefly on the improved COM interoperability that is coming along with that. This article will build on that and provide specifics.

Optional and Named Parameters

Traditionally C# has avoided the implementation of optional and named parameters. The thought process being that overloading could provide much of what was necessary. The following example demonstrates sample method footprints for a method to open a text file and several overloads for it.

  public StreamReader OpenTextFile(
      string path,
      Encoding encoding,
      bool detectEncoding,
      int bufferSize); 
  
  public StreamReader OpenTextFile(
      string path,
      Encoding encoding,
      bool detectEncoding);
  
  public StreamReader OpenTextFile(
      string path,
      Encoding encoding);
  
  public StreamReader OpenTextFile(string path);

However, with the commitment to co-evolution between C# and Visual Basic it is necessary for C# to join with the ranks of VB and support optional and named parameters. The revised example using optional parameters is below. This creates the ability to vary the method calls with only a single definition.

  // With optional parameters
  public StreamReader OpenTextFile(
      string path,
      Encoding encoding = null,
      bool detectEncoding = true,
      int bufferSize = 1024); 
  
  // Method call excluding the last two parameters
  OpenTextFile("foo.txt", Encoding.UTF8);

In order to allow for any and all parameters to be optional, the concept of named parameters goes hand-in-hand.

  • Named arguments can appear in any order as long as all names are given
  • Named arguments must be last in the list of parameters if not all parameters are named
  • Arguments are evaluated in the order given
  • Non-optional parameters must always be specified

  // Uses a named argument in last position
  OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096);
  
  // Uses named parameters to reorder the parameters and leave one out
  OpenTextFile(
      bufferSize: 4096,
      path: "foo.txt",
      detectEncoding: false);

Optional and named parameters have a direct benefit to COM Interoperability. The following example represents code that would previously have been required to create and save a Word document.

  object fileName = "Test.docx";
  object missing  = System.Reflection.Missing.Value;
  doc.SaveAs(ref fileName,
      ref missing, ref missing, ref missing,
      ref missing, ref missing, ref missing,
      ref missing, ref missing, ref missing,
      ref missing, ref missing, ref missing,
      ref missing, ref missing, ref missing);

With optional and named parameters, the above example can be heavily simplified to the simple code below, which results in Office automation and other code finally looking the way it was intended to look.

  doc.SaveAs("Test.docx");

Automatic Object to Dynamic Mapping

The Dynamic Language Runtime (DLR) introduces the concept of object binders. By default the DLR includes a COM binder that maps dynamic types to statically typed .NET objects. The following sample code shows a snippet of code that is part of reading all of the processes on the local machine and then graphing resources in Excel. Note the heavy use of casting within the code and how it makes the code much more complicated to read.

  xl.Workbooks.Add(Type.Missing);
  xl.Visible = true;
  
  ((Excel.Range)xl.Cells[1, 1]).Value2 = "Process Name";
  ((Excel.Range)xl.Cells[1, 2]).Value2 = "Memory Usage";
  
  int i = 2;
  foreach (var proc in (from p in Process.GetProcesses()
                           orderby p.VirtualMemorySize64 descending
                                    select p).Take(20))
  {
              ((Excel.Range)xl.Cells[i, 1]).Value2 = proc.ProcessName;
              ((Excel.Range)xl.Cells[i, 2]).Value2 = proc.VirtualMemorySize64;
              i++;
  }
  
  Excel.Range cellRange = (Excel.Range)xl.Cells[1, 1];
  
  Excel.Chart xlChart = (Excel.Chart)xl.ActiveWorkbook.Charts.
  Add(Type.Missing, xl.ActiveSheet, Type.Missing, Type.Missing);

The following code has been revised to rely on the object binder to do the mapping:

  //Optional parameters 
  xl.Workbooks.Add();
  xl.Visible = true;
  
  //Automatic conversion into dynamic
  xl.Cells[1, 1].Value2 = "Process Name";
  xl.Cells[1, 2].Value2 = "Memory Usage";
  
  int i = 2;
  foreach (var proc in (from p in Process.GetProcesses()
                                    orderby p.VirtualMemorySize64 descending
                                    select p).Take(20))
  {
              //Automatic conversion into dynamic
              xl.Cells[i, 1].Value2 = proc.ProcessName;
              xl.Cells[i, 2].Value2 = proc.VirtualMemorySize64;
              i++;
  }
  
  //Equality Conversion
  Excel.Range cellRange = xl.Cells[1, 1];
  
  //Equality Conversion + Named Parameters + Optional Parameters
  Excel.Chart xlChart = xl.ActiveWorkbook.Charts.Add(After:xl.ActiveSheet);

Optional "ref" Modifier

With the next release of the .NET Framework you will be able to omit the "ref" keyword in some cases when talking to COM.

Interop Type Embedding ("No PIA")

Another feature being introduced that will yield COM Interoperability improvements has to do with not requiring the primary interop assembly (PIA). Traditionally there would have been a number of additional DLLs you would have had to deploy with your application to support specialized types. These types can be embedded directly in to the application now, which means you don't need the primary assembly at all to utilize these types.

Summary

You have now seen some of the COM interoperability improvements that are coming along with the DLR such as optional and named parameters. The introduction of this functionality should make COM Interop code not only easier to write, but also to read and maintain in the long run.

Future Columns

The topic of the next column is likely to be more on the benefits coming with .NET Framework 4.0. If you have something else in particular that you would like to see explained here you could reach me at mark.strawmyer@crowehorwath.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds