1

Consider the following function:

static void Main(string[] args)
{
    FileStream fs = new FileStream("e:\\temp.txt", FileMode.Open);
    int size = (int)fs.Length;

    byte[] data = new byte[size];
    IAsyncResult result = fs.BeginRead(data, 0, size, new AsyncCallback(Callback), fs);

    Console.ReadLine();
}

Question1: If I put a breakpoint on BeginRead line, and run the program in debug mode, I get the following error:

An unhandled exception of type 'System.AccessViolationException' occurred in MyApp.exe.

However, if I put the breakpoint on the ReadLine line and do the same the error doesn't occur. I believe passing the FileStream instance as the last parameter to the BeginRead function causes the problem, however, I've no idea what is happening there.

---UPDATE1: You might ask why I'm trying to pass "fs" to the callback. Yes, I can hold it as a member variable however what if I was going to read multiple files asynchronously? That way, holding an array (or list) of file streams would be irrational.

Question2: AFAIK, IAsyncResult is defined as follows:

[ComVisible(true)]
public interface IAsyncResult
{
    object AsyncState { get; }
    WaitHandle AsyncWaitHandle { get; }
    bool CompletedSynchronously { get; }
    bool IsCompleted { get; }
}

However, when tracing the code, I've noticed other members on IAsyncResult:

enter image description here

How's this possible? The IAsyncResult is obviously implemented by ReadWriteTask class (in this case), however, I don't get where those other properties come from.

---Update 2: I tried to mimic the same using the following code:

public interface IMyInterface
{
    int Prop1 { get; }
}

public class Impl : IMyInterface
{
    public int Prop1 { get { return 101; } }
    public int Prop2 { get { return 202; } }
}

public class MyClass
{
    public IMyInterface GetMyInterface()
    {
        Impl impl = new Impl();
        return impl;
    }
}

And to invoke the method, I just instantiate a MyClass and call the GetMyInterface method as follows:

MyClass c = new MyClass();
IMyInterface my = c.GetMyInterface();

However, when I watch the my variable in Quickwatch, I see the non-flattened result which is totally OK with me. However, this is not the same case for IAsyncResult / ReadWriteTask. What's the difference?

enter image description here

Joe Bank
  • 653
  • 7
  • 20
  • Ad **UPDATE1**: Well, if you're doing that, where are you storing the output buffer (`data`)? Your encapsulation is all wrong, all the structures necessary for handling the request should be separate from the main code. – Luaan Jul 07 '14 at 08:40
  • Ad **UPDATE2**: Interesting. Seems there's some minor difference we're ignoring. Or it might simply be that there's some special cases in the debugger, it certainly wouldn't be the first one I've seen. In any case, it's just a curiosity - it shouldn't have any effect on what's happening. – Luaan Jul 08 '14 at 07:09

1 Answers1

2

IAsyncResult is just an interface. You can easily see that the actual type of the variable in this case is System.IO.Stream.ReadWriteTask - it just implements the interface IAsyncResult. That means it has to have the properties of IAsyncResult, but it can have whatever else it wants as well. If you cast the variable to ReadWriteTask, you'll see the other properties and methods in IntelliSense too, and you can use them (although you probably shouldn't). You might want to brush up on what class and interface is.

Make sure the file is actually accessible. You might be doing something that prevents you from successfully opening the file in code - e.g. having the file open in some other application.

There's no reason to pass the file stream as state. It shouldn't hurt either, though.

Also, why are you using BeginRead? You're running .NET 4.5 (as evidenced by the ReadWriteTask returned by BeginRead), so why not simply use var bytesRead = await fs.ReadAsync(...);? In fact, with proper usage, you wouldn't need the ReadLine at all - you should wait for the completion of whatever it is you're actually doing instead.

Of course, in this case, asynchronous I/O is pointless anyway, but I assume this is just a sample and you intend to do something more useful with it.

EDIT:

This is a full working snippet that doesn't display your error:

using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncFileStream
{
  class Program
  {
    static void Main(string[] args)
    {
      FileStream fs = new FileStream("d:\\temp.txt", FileMode.Open);
      int size = (int)fs.Length;

      byte[] data = new byte[size];

      var result = 
          fs.BeginRead(data, 0, size, (ar) => Callback(fs, ar, data), null);

      if (result.CompletedSynchronously) Callback(fs, result, data);

      Console.ReadLine();
    }

    static void Callback(FileStream fs, IAsyncResult ar, byte[] data)
    {
      var bytesRead = fs.EndRead(ar);

      Console.WriteLine(UTF8Encoding.UTF8.GetString(data, 0, bytesRead));
    }
  }
}

Does this display the same error you were having with your code? If not, you might want to add code for your callback method and probably some more relevant information.

Disclaimer: This is still a bad way to read from a file. There's no guarantee that you'll get all the data in one read, and in fact, very often, reading the whole file at once is a huge waste of resources and completely unnecessary.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • The file is accessible, I'm 100% sure. The error happens just by moving the breakpoint as described in the question. For the other question, if you pay close attention to the quick watch window, you'll see that all properties are flattened which is not possible when doing with my own Interface. On the other hand, ReadWriteTask is a "private", "sealed" class defined within the abstract Stream class. So, this cannot be the case. Any other idea? (and yes, it's just a sample, I'm not going to use this). – Joe Bank Jul 07 '14 at 07:54
  • 1
    @JoeBank You're still confusing classes and interfaces. The properties are "flattened", because there is no base type `IAsyncResult` - you're simply seeing the properties of the type `Task`, which happens to implement `IAsyncResult`. Since no other class in the inheritance chain has its own public properties or methods, you're seeing `Task`'s. The same thing happens when you use interfaces of your own. Also, the fact that `ReadWriteTask` is `private sealed` is completely irrelevant. The return value is `IAsyncResult`, and that's important. The fact that it's `Task` is an implementation detail. – Luaan Jul 07 '14 at 08:32
  • Well, I tried your code in a clean Console App, and still the same error happens (if I put the breakpoint at BeginRead line). Maybe debugger is trying to do something which corrupts the memory, I don't know. Does the same thing happen to you? I'm using Win7 (64bit), .NET Framework 4.5, Visual Studio 2013 Update 2. – Joe Bank Jul 08 '14 at 03:36
  • I updated the question (update2) for that class/interface thing. Would you please check it out? I really need to understand what's happening there. Thank you. – Joe Bank Jul 08 '14 at 03:50
  • 1
    @JoeBank I've got the very same configuration, in fact, and I don't have the issue you're getting. Perhaps a Visual Studio reinstall is in order? :D I've seen the debugger get wonky a few times (never on my computer, though), so I guess it can get a bit finicky if something goes wrong with its environment. Do you have any add-ons installed in VS? .NET Reflector and ReSharper tend to break VS rather often :) – Luaan Jul 08 '14 at 07:12