Note that there are some explanatory texts on larger screens.

plurals
  1. POMultiplexing interface method calls into a single delegate and demultiplexing
    text
    copied!<p>The short version of what I am looking for is this:</p> <p>I am looking for a mechanism which, given an interface, will dynamically generate a pair of classes for that interface, one multiplexer and one demultiplexer, which will convert calls to/from a general-purpose delegate of the following form: <code>object AnyCall( int method_selector, object[] arguments )</code>. The multiplexer class will accept an AnyCall delegate as a construction-time parameter, and it will implement the interface by delegating every call to the delegate. The demultiplexer class will accept a reference to the interface as a construction-time parameter, and it will implement the delegate by switching on the method selector and invoking the appropriate method of the interface, passing it the parameters that were passed to the delegate.</p> <p>The long version of what I am looking for is this:</p> <p>Consider the following interface:</p> <pre><code>public interface IFooable { void Moo( int i ); void Boo( string s, bool b ); } </code></pre> <p>And consider the following class implementing that interface:</p> <pre><code>public class FooImplementation: IFooable { void IFooable.Moo( int i ) { System.Console.WriteLine( "i: " + i ); } void IFooable.Boo( string s, bool b ) { System.Console.WriteLine( "s: " + s + ", b: " + b ); } } </code></pre> <p>And then consider the following class making use of the above:</p> <pre><code>public partial class MuxdemTest { public static void InvokeFoo( IFooable fooable ) { fooable.Moo( 42 ); fooable.Boo( "fubar!", true ); } public static void Run1() { IFooable fooable = new FooImplementation(); InvokeFoo( fooable ); } } </code></pre> <p>Nothing fancy here.</p> <p>Now let us suppose that instead of giving InvokeFoo() a direct reference to FooImplementation I would like to embed some functionality inbetween the two that would allow me to do some really useful things with the interface method calls, like, say, count the number of times a call was made to one of the methods of the interface; or convert the calls into messages and deliver them to a FooImplementation that resides on a different thread; or on a different continent; or whatever. And of course this inbetween functionality should be able to work on ANY interface, not just IFooable.</p> <p>In order to achieve this, we need a way to multiplex calls to methods of an interface into invokations of a single general-purpose delegate, and later demultiplex them from invokations to that delegate into interface method calls. The delegate I am thinking of would have the following form:</p> <pre><code>public delegate object AnyCall( int method_selector, object[] arguments ); </code></pre> <p>So, here is an implementation of a multiplexer for the IFooable interface:</p> <pre><code>public class MuxForFooable: IFooable { private readonly AnyCall AnyCall; public MuxForFooable( AnyCall anycall ) { AnyCall = anycall; } void IFooable.Moo( int i ) { AnyCall( 0, new object[]{ i } ); } void IFooable.Boo( string s, bool b ) { AnyCall( 1, new object[]{ s, b } ); } } </code></pre> <p>And here is an implementation of a demultiplexer for the IFooable interface:</p> <pre><code>public class DemuxForFooable { public readonly IFooable Target; public DemuxForFooable( IFooable target ) { Target = target; } public object AnyCall( int method_selector, object[] arguments ) { switch( method_selector ) { case 0: Target.Moo( (int)arguments[0] ); break; case 1: Target.Boo( (string)arguments[0], (bool)arguments[1] ); break; default: throw new System.InvalidOperationException(); } return null; } } </code></pre> <p>And here is a piece of code that makes use of the above, achieving exactly the same thing as the Run1() method above, the difference now being that all calls pass through an 'AnyCall' delegate:</p> <pre><code>public partial class MuxdemTest { public static void Run2() { IFooable fooable = new FooImplementation(); DemuxForFooable demux = new DemuxForFooable( fooable ); MuxForFooable mux = new MuxForFooable( demux.AnyCall ); InvokeFoo( mux ); } } </code></pre> <p>My only problem is that the classes MuxForFooable and DemuxForFooable have been hand-written, while I want them dynamically generated. Consider the following mock methods that would generate them, and a piece of code that would use those methods:</p> <pre><code>public partial class MuxdemTest { public static T CreateMux&lt;T&gt;( AnyCall anycall ) { if( typeof(T) == typeof(IFooable) ) return (T)(IFooable)new MuxForFooable( anycall ); throw new System.NotImplementedException(); } public static AnyCall CreateDemux&lt;T&gt;( T target ) { if( typeof(T) == typeof(IFooable) ) return new DemuxForFooable( (IFooable)target ).AnyCall; throw new System.NotImplementedException(); } public static void Run3() { IFooable fooable = new FooImplementation(); AnyCall demux = CreateDemux&lt;IFooable&gt;( fooable ); IFooable mux = CreateMux&lt;IFooable&gt;( demux ); InvokeFoo( mux ); } } </code></pre> <p>Run3() above has exactly the same effect as Run2() and Run1() further above.</p> <p><strong>So, has anyone ever written or knows how to write actual implementations for CreateMux() and CreateDemux()?</strong></p> <p>You may assume that the interfaces will contain only methods and no properties, and that all methods will return void and will not accept any "ref" nor "out" parameters. (Even though I would not mind an implementation that would allow these things.)</p> <p>There are lots of code samples out there that do things similar to what I want, but I am posting this question in the hope that someone has already done exactly what I want to do, because the subject of dynamic code generation is very tricky.</p> <p>I am aware that what I want can be accomplished with existing proxy frameworks like CastleProxy, but I do not want to use an entire external framework for such a simple task, nor do I want the runtime overhead incurred by the use of such a framework. I looked at the source code of CastleProxy trying to figure out how to use parts of it to do what I want, but I found it way too convoluted to make any sense out of it.</p> <h1>Edit 1:</h1> <p>Six months later, I implemented a tool which does what I was asking for in this question. I am going to publish a paper about it, but before I do that, I need help with the naming, so I opened another question: <a href="https://codereview.stackexchange.com/questions/6309/need-help-with-naming-marshaling-interface-calls">Need help with naming (marshaling interface calls)</a></p> <p>In the mean time, please feel free to add an answer if you have one.</p> <h1>Edit 2:</h1> <p>I decided to call the tool <em>"intertwine"</em>, and the operations <em>"entwine"</em> and <em>"untwine"</em>. If you want to read about it, here it is: <a href="http://blog.michael.gr/2011/10/intertwine-normalizing-interface.html" rel="nofollow noreferrer">michael.gr - Intertwine: Normalizing Interface Invocations</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload