Howdy,
I've just completed the first pass of an implementation of the Ice protocol within the .NET framework, in C#. It interoperates fully with and is built on top of the .NET Remoting infrastructure. (Note that the namespace name will change to avoid trademark issues if any, but "Ice" is just too convenient for now!)
The runtime is fully dynamic; all classes, method invocations, etc., are serialized using the Reflection functionality of the CLI. This means that slice2cs just translates the slice definitions into similar abstract C# class declarations. (Using slice and slice2cs isn't really necessary, though it is of course necessary for interoperability with the C++ and Java runtimes.) This is a performance hit when marshalling complex objects -- however, in the future, I plan to create type-specific marshalling code at runtime, and then cache and execute that code (JIT marshaller/demarshaller creation).
Because it's integrated into the .NET Remoting framework, the same objects can be made available via Ice, SOAP, or any of the other available .NET Remoting backends just by adding another channel. (See example below.) Also, already existing generic bits, like the object lifetime management services, work.
Sample server:
Code:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
// this would be automatically generated from slice
public abstract class Hello : Ice.Object {
public abstract int sayHello(string[] who);
}
public class HelloI : Hello {
public override int sayHello(string[] who) {
foreach (string w in who) {
Console.WriteLine ("Hello " + w);
}
return who.Length;
}
}
public class Driver {
public static void Main () {
Ice.IceChannel ic = new Ice.IceChannel (10000); // port
ChannelServices.RegisterChannel (ic);
// the next two lines create a SOAP channel; our object
// is available on this channel as well.
HttpChannel hc = new HttpChannel (9000); // port
ChannelServices.RegisterChannel (hc);
// if we were to specify WellKnownObjectMode.SingleCall,
// a new HelloI instance would be created for each invocation.
RemotingConfiguration.RegisterWellKnownServiceType (typeof (HelloI),
"hello",
WellKnownObjectMode.Singleton);
Console.ReadLine();
}
}
And the accompanying client:
Code:
using System;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
// this is automatically generated from the .ice IDL
public abstract class Hello : Ice.Object {
public abstract int sayHello(string[] who);
}
public class Driver {
public static void Main () {
Ice.IceChannel ic = new Ice.IceChannel ();
ChannelServices.RegisterChannel (ic);
Hello h = (Hello) Activator.GetObject (typeof (Hello), "ice://localhost:10000/hello");
string[] who = {".NET", "Mono", "C#"};
int ret = h.sayHello(who);
Console.WriteLine ("Said " + ret + " hellos.");
}
}
Note that I could have requested an Ice.Object instead; the cast to (Hello) would have resulted in a round-trip to ice_ids() to verify that the object can indeed be cast to a Hello class.
There's still a lot of work to do, mainly with tying down exactly how Proxies/ObjRefs are handled and passed, verifying the protocol marshaller/demarshaller, implementing the asynchronous message processing stuff (no extra work is required by client or server code to invoke a message asynchronously, but some extra plumbing needs to go in), and eventually optimizations.
As far as language overhead, an equivalent C# latency/ice_ping test takes about three times as long as the native C++ version; this is using the Mono runtime on linux, which runs at about half-3/4 the speed of the microsoft runtime. Considering that I've made no attempt to optimize anything, this isn't too bad

The implementation is already (mostly) CLS compliant, meaning that it should be usable from Visual Basic, Visual J#, SML.NET, etc.