views:

115

answers:

1

I am trying to do async IO using BeginRead() in JScript.NET, but I can't get the callback function to work correctly.

Here is the code:

function readFileAsync() {
    var fs : FileStream = new FileStream( 'test.txt', FileMode.Open, FileAccess.Read );
    var result : IAsyncResult = fs.BeginRead( new byte[8], 0, 8, readFileCallback ), fs );
    Thread.Sleep( Timeout.Infinite );
}

var readFileCallback = function( result : IAsyncResult ) : void {
 print( 'ListenerCallback():' );
}

The exception is a cast failure:

Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'Microsoft.JScript.Closure' to type 'System.AsyncCallback'.
at JScript 0.readFileAsync(Object this, VsaEngine vsa Engine)
at JScript 0.Global Code()
at JScript Main.Main(String[] )

I have tried doing an explicit cast both to AsyncCallback and to the base MulticastDelegate and Delegate types to no avail.

Delegates are supposed to be created automatically, obviating the need for creating a new AsyncCallback explicitly, eg:

BeginRead( ... new AsyncDelegate( readFileCallback), object );

And in fact if you try to create the delegate explicitly the compiler issues an error. I must be missing something here.

+1  A: 

The problem stemmed from the fact that internally a delegate is created using

Delegate.CreateDelegate( Type, Object, String ) 

where Type is the delegate type to create, Object is the instance on which the method will be invoked and String is the name of the method. In order for this to work, the function must be an instance method, so we must define a class as such:

class AsyncFileReader 
{
    function readFileAsync() {
        var fs : FileStream = new FileStream( 
            'test.txt', FileMode.Open, FileAccess.Read 
        );

        var result : IAsyncResult = fs.BeginRead( 
            new byte[8], 0, 8, ListenerCallback, fs 
        );
        // Sleep just for testing
        Thread.Sleep( Timeout.Infinite );
    }

    function ListenerCallback( result : IAsyncResult ) : void {
        print( 'ListenerCallback():' );
    }

} // class

Since the callback can now bound to an instance of AsyncFileReader at runtime, the conversion will succeed. The error listed above was most likely one of my attempts at explicitly casting, which is not what takes place during the conversion here.

dnewcome