1

考虑以下函数:

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();
}

问题 1: 如果我在 BeginRead 行设置断点,并在调试模式下运行程序,我会收到以下错误:

MyApp.exe 中发生了“System.AccessViolationException”类型的未处理异常。

但是,如果我将断点放在 ReadLine 行并执行相同操作,则不会发生错误。我相信将 FileStream 实例作为最后一个参数传递给 BeginRead 函数会导致问题,但是,我不知道那里发生了什么。

---UPDATE1:您可能会问我为什么要尝试将“fs”传递给回调。是的,我可以将它作为成员变量保存,但是如果我要异步读取多个文件怎么办?这样,保存文件流的数组(或列表)将是不合理的。

问题2: AFAIK,IAsyncResult 定义如下:

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

但是,在跟踪代码时,我注意到 IAsyncResult 上的其他成员:

在此处输入图像描述

这怎么可能?IAsyncResult 显然是由 ReadWriteTask 类(在这种情况下)实现的,但是,我不知道其他属性的来源。

---更新2: 我尝试使用以下代码来模仿:

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;
    }
}

为了调用该方法,我只需实例化一个 MyClass 并调用 GetMyInterface 方法,如下所示:

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

但是,当我在 Quickwatch 中观看 my 变量时,我看到了非扁平化结果,这对我来说完全没问题。但是,IAsyncResult / ReadWriteTask 的情况不同。有什么不同?

在此处输入图像描述

4

1 回答 1

2

IAsyncResult只是一个界面。您可以很容易地看到,在这种情况下,变量的实际类型是System.IO.Stream.ReadWriteTask- 它只是实现了接口IAsyncResult。这意味着它必须具有 的属性IAsyncResult,但它也可以具有它想要的任何其他属性。如果将变量强制转换为ReadWriteTask,您还将在 IntelliSense 中看到其他属性和方法,并且您可以使用它们(尽管您可能不应该使用它们)。你可能想复习一下什么classinterface是什么。

确保该文件实际上是可访问的。您可能正在做一些事情,阻止您在代码中成功打开文件 - 例如在其他应用程序中打开文件。

没有理由将文件流作为状态传递。不过,它也不应该受到伤害。

另外,你为什么用BeginRead?您正在运行 .NET 4.5(由ReadWriteTask返回的证明BeginRead),那么为什么不简单地使用var bytesRead = await fs.ReadAsync(...);呢?事实上,如果使用得当,你根本不需要ReadLine- 你应该等待完成你实际上正在做的任何事情。

当然,在这种情况下,异步 I/O 无论如何都是没有意义的,但我认为这只是一个示例,您打算用它做一些更有用的事情。

编辑

这是一个完整的工作片段,不显示您的错误:

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));
    }
  }
}

这是否显示与您的代码相同的错误?如果没有,您可能需要为您的回调方法添加代码,并可能需要一些更相关的信息。

免责声明:这仍然是从文件中读取的不好方法。不能保证一次读取就可以获取所有数据,事实上,很多时候一次读取整个文件是一种巨大的资源浪费,而且完全没有必要。

于 2014-07-07T07:26:46.303 回答