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: 私の知る限り、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 にも他のプロパティとメソッドが表示され、それらを使用できるようになります (使用しないでください)。classあなたは何と何であるかをブラッシュアップしたいかもしれませんinterface

ファイルが実際にアクセス可能であることを確認してください。コードでファイルを正常に開けないようなことをしている可能性があります。たとえば、ファイルを他のアプリケーションで開いている場合などです。

ファイル ストリームを状態として渡す理由はありません。とはいえ、どちらも痛くないはずです。

また、なぜ使用しているの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));
    }
  }
}

これは、コードで発生していたのと同じエラーを表示しますか? そうでない場合は、コールバック メソッドのコードを追加し、さらに関連情報を追加することをお勧めします。

免責事項: これは、ファイルから読み取るにはまだ悪い方法です。1 回の読み取りですべてのデータを取得できるという保証はありません。実際、ファイル全体を一度に読み取ることは、リソースの膨大な浪費であり、完全に不要な場合がよくあります。

于 2014-07-07T07:26:46.303 に答える