MathGroup Archive 2004

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Mathematica + NETLink + CodeDom- Example 2

  • To: mathgroup at smc.vnet.net
  • Subject: [mg45356] Re: [mg45304] Mathematica + NETLink + CodeDom- Example 2
  • From: Todd Gayley <tgayley at wolfram.com>
  • Date: Fri, 2 Jan 2004 04:23:45 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

At 11:22 PM 12/28/2003, ToolmakerSteve wrote:
>(Follow on to [mg45085] NETLink - CREATING a new class?
>I have submitted this to support@wolfram,
>and explained that I hope it will be given to a programmer
>who is working on NETLink -


He's now back from vacation....


>so that the problems I encountered in mg45085 can be resolved,
>and so that some example like this can be included in the NETLink 
>documentation,
>in hopes that some other O-O .NET programmers can be enticed to use 
>Mathematica.
>)


Back in mg45085, the problem was:

>"NET::nomethod: No public instance method named CompileAssemblyFromDom exists
>for the .NET type Microsoft.CSharp.CSharpCodeGenerator."

And the offending code was:

>     csharp = NETNew[ "Microsoft.CSharp.CSharpCodeProvider" ];
>     cscompiler = csharp@CreateCompiler[];
>     result = cscompiler@CompileAssemblyFromDom[ compParams, compUnit1 ];

The problem here is subtle, and it was a limitation in the first version of 
.NET/Link. The issue is that the actual class of the cscompiler object 
(Microsoft.CSharp.CSharpCodeGenerator) is private. Although this class 
implements the public ICodeCompiler interface, and therefore has a public 
method named CompileAssemblyFromDom, .NET/Link cannot invoke the method 
because the class is private. In a compiled .NET language program this is 
not a problem because the cscompiler object would be typed as the public 
ICodeCompiler interface, not its actual private runtime class type:

     // C# code.
     ICodeCompiler cscompiler = csharp.CreateCompiler();
     result = cscompiler.CompileAssemblyFromDom(...);

.NET/Link 1.1 includes a CastNETObject function that allows you to upcast 
the cscompiler object to the ICodeCompiler interface type. This would allow 
the method to be called just like in a C# program:

     cscompiler = CastNETObject[csharp@CreateCompiler[], 
"System.CodeDom.Compiler.ICodeCompiler"];
     result = cscompiler@CompileAssemblyFromDom[ compParams, compUnit1 ];

The 1.1 version of .NET/Link ships with Mathematica 5.0.1 and will be 
available for general download in the very near future at 
www.wolfram.com/solutions/mathlink/netlink.

In the meantime, you can work around the problem by manually using 
reflection to invoke the CompileAssemblyFromDom method defined in the 
ICodeCompiler interface:

     iccType = 
GetTypeObject[LoadNETType["System.CodeDom.Compiler.ICodeCompiler"]];
     meth = iccType@GetMethod["CompileAssemblyFromDom"];
     result = meth@Invoke[cscompiler, {compParams, compUnit1}];


There is another small issue in your old and new code--the problem you had 
with doing a BitOr merging of the MemberAttributes`Public and 
MemberAttributes`Static enum values. Normally this will work in .NET/Link, 
and your NetBitOr function is the correct way to do (flag1 | flag2) 
constructions in Mathematica (this is documented in the new .NET/Link 1.1 
User Guide):

     NetBitOr[ net1_, net2_ ]:=
        BitOr[ NETObjectToExpression[ net1 ], NETObjectToExpression[ net2 ] ]

The reason it doesn't work for the MemberAttributes enum is that for some 
reason this enum is not decorated with the [Flags] attribute, which is 
supposed to be applied to all enums that can have values bitor-ed together. 
It looks like a bug in the .NET Framework that the [Flags] attribute was 
left off the MemberAttributes enum. You can work around the problem by 
manually constructing an enum value of the right type by using the .NET 
Framework's Enum.ToObject() function:

     memberAttributesType = 
GetTypeObject[LoadNETType["System.CodeDom.MemberAttributes"]];
     LoadNETType["System.Enum"];
     attrs = Enum`ToObject[memberAttributesType,
               MakeNETObject[NetBitOr[MemberAttributes`Public, 
MemberAttributes`Static]]];


>Here is a more interesting notebook,
>which creates a .NET assembly without
>having to type all those "NETNew" expressions.
>
>It contains a package "NetCodeGen",
>which is a translator from a simple structure in Mathematica,
>which represents the assembly as code snippets within some structural
>constructs.
>
>(By The Way, this is far more readable than the XML version of code that some
>people are starting to work with in other environments.)


Your approach is interesting, and I suggest you continue developing it, 
especially with an eye to allowing users to provide method implementations 
in the Mathematica language instead of only embedding strings of C# code in 
a Mathematica expression structure. This is quite similar to work that was 
in the development version of .NET/Link but pulled out before release 
because it was beyond the scope of a 1.0 release. Basically, it was decided 
that there was not sufficient time for the considerable design work 
required. Methods like DefineNETClass and NETMethod were once part of 
.NET/Link. Presumably, functionality like this will be introduced in a 
future release.


Todd Gayley
Wolfram Research 


  • Prev by Date: Re: RunThrough on Windows 2000
  • Next by Date: Wishart Distribution
  • Previous by thread: Re: How to copy pattern from one expression to another?
  • Next by thread: Re: Mathematica + NETLink + CodeDom- Example 2