Cross-language Extension Method Calling

Posted by Tom Hines on Geeks with Blogs See other posts from Geeks with Blogs or by Tom Hines
Published on Fri, 05 Mar 2010 23:22:11 GMT Indexed on 2010/03/07 23:28 UTC
Read the original article Hit count: 495

Filed under:

Extension methods are a concise way of binding functions to particular types.

In my last post, I showed how Extension methods can be created in the .NET 2.0 environment.
In this post, I discuss calling the extensions from other languages.

Most of the differences I find between the Dot Net languages are mainly syntax.  The declaration of Extensions is no exception.  There is, however, a distinct difference with the framework accepting excensions made with C++ that differs from C# and VB. 

When calling the C++ extension from C#, the compiler will SOMETIMES say there is no definition for DoCPP with the error:
'string' does not contain a definition for 'DoCPP' and no extension method 'DoCPP' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

If I recompile, the error goes away.

The strangest problem with calling the C++ extension from C# is that I first must make SOME type of reference to the class BEFORE using the extension or it will not be recognized at all.  So, if I first call the DoCPP() as a static method, the extension works fine later.  If I make a dummy instantiation of the class, it works.  If I have no forward reference of the class, I get the same error as before and recompiling does not fix it.  It seems as if this none of this is supposed to work across the languages.

I have made a few work-arounds to get the examples to compile and run.

Note the following examples:


Extension in C#

using System;

namespace Extension_CS
{
   public static class CExtension_CS
   {  //in C#, the "this" keyword is the key.
      public static void DoCS(this string str)
      {
         Console.WriteLine("CS\t{0:G}\tCS", str);
      }
   }
}



Extension in C++

/****************************************************************************\
 * Here is the C++ implementation.  It is the least elegant and most quirky,
 * but it works.
\****************************************************************************/
#pragma once
using
namespace System;
using namespace System::Runtime::CompilerServices;     //<-Essential
// Reference: System.Core.dll //<- Essential

namespace Extension_CPP {
       public ref class CExtension_CPP
       {
       public:
              [Extension] // or [ExtensionAttribute] /* either works */
              static void DoCPP(String^ str)
              {
                     Console::WriteLine("C++\t{0:G}\tC++", str);
              }
       };
}


Extension in VB

' Here is the VB implementation.  This is not as elegant as the C#, but it's
' functional.
Imports System.Runtime.CompilerServices
'
Public Module modExtension_VB 'Extension methods can be defined only in modules.
   <Extension()> _
      Public Sub DoVB(ByVal str As String)
      Console.WriteLine("VB" & Chr(9) & "{0:G}" & Chr(9) & "VB", str)
   End Sub
End
Module

 


Calling program in C#

/******************************************************************************\
 * Main calling program
 * Intellisense and VS2008 complain about the CPP implementation, but with a
 * little duct-tape, it works just fine.
\******************************************************************************/
using System;
using Extension_CPP;
using Extension_CS;
using Extension_VB; // vitual namespace

namespace TestExtensions
{
   public static class CTestExtensions
   {
      /**********************************************************************\
       * For some reason, this needs a direct reference into the C++ version
       * even though it does nothing than add a null reference.
       * The constructor provides the fake usage to please the compiler.
      \**********************************************************************/
      private static CExtension_CPP x = null;   // <-DUCT_TAPE!
      static CTestExtensions()
      {
         // Fake usage to stop compiler from complaining
         if (null != x) {} // <-DUCT_TAPE
      }

      static void Main(string[] args)
      {
         string strData = "from C#";
         strData.DoCPP();
         strData.DoCS();
         strData.DoVB();
      }
   }
}

 


Calling program in VB 

Imports Extension_CPP
Imports Extension_CS
Imports Extension_VB
Imports System.Runtime.CompilerServices

Module TestExtensions_VB
   <Extension()> _
     
Public Sub DoCPP(ByVal str As String)
     
'Framework does not treat this as an extension, so use the static
      CExtension_CPP.DoCPP(str)
  
End Sub

   Sub Main()
     
Dim strData As String = "from VB"
      strData.DoCS()
      strData.DoVB()
      strData.DoCPP()
'fake
   End Sub
End
Module



 Calling program in C++

// TestExtensions_CPP.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace Extension_CPP;
using namespace Extension_CS;
using namespace Extension_VB;

void main(void)
{
      
/*******************************************************\
        * Extension methods are called like static methods
        * when called from C++.  There may be a difference in
        * syntax when calling the VB extension as VB Extensions
        * are embedded in Modules instead of classes
       \*******************************************************/
    String^ strData = "from C++";
    CExtension_CPP::DoCPP(strData);
    CExtension_CS::DoCS(strData);
    modExtension_VB::DoVB(strData);
//since Extensions go in Modules
}



 

 

© Geeks with Blogs or respective owner