4

次のコードが a を返す理由がCannot resolve method Write(T)わかりません - 私には明白に思えます:

    private static void WriteToDisk<T>(string fileName, T[] vector)
    {
        using (var stream = new FileStream(fileName, FileMode.Create))
        {
            using (var writer = new BinaryWriter(stream))
            {
               foreach(T v in vector) writer.Write(v);
                writer.Close();
            }
        }
    }

int[]long[]または などのベクトルを処理できる一般的なバイナリ書き込みメソッドを定義したいと思いますdouble[]

4

4 に答える 4

10

呼び出すオーバーロードはWrite()、実行時ではなく、コンパイル時に決定されます。 この方法でメソッドを呼び出せるようにするには、オーバーロード(または一般的なオーバーロード)BinaryWriterが必要になります。このエラーは(正しく)どちらも持っていないことを示しています。Write(object)Write<T>(T)

object(または一般的に型指定された引数)を受け入れ、その型を調べBinaryWriter.Write()て呼び出すオーバーロードを決定する独自のラッパーメソッドを作成する必要があります。

于 2013-01-02T22:39:29.343 に答える
3

cdhowie には正しい説明があります。オーバーロードの解決はコンパイル時に行われます。この場合、 については何もわかってTいないため、オーバーロードは適用されません。

ではdynamic、オーバーロードの解決は実行時に行われます。多分あなたは使うことができます:

writer.Write((dynamic)v)

実行時にボクシングとオーバーロードの解決が繰り返されるため、少し遅くなります。

編集:何らかの理由でにアクセスできない場合はdynamic、明示的なリフレクションで同様の動作を得ることができます:

private static void WriteToDisk<T>(string fileName, T[] vector)
{
    var correctMethod = typeof(BinaryWriter).GetMethod("Write", new[] { typeof(T), });
    if (correctMethod == null)
        throw new ArgumentException("No suitable overload found for type " + typeof(T), "T");
    using (var stream = new FileStream(fileName, FileMode.Create))
    {
        using (var writer = new BinaryWriter(stream))
        {
           foreach(var v in vector)
               correctMethod.Invoke(writer, new object[] { v, });
        }
    }
}

これが よりも速いか遅いかはわかりませんdynamic

どちらの場合でも、 でサポートされていない型T( など) を誤って使用した場合、すべてが正常にコンパイルされ、実行時 (コードの実行時) にのみ間違いを発見できます。メソッドにデリゲート インスタンスを渡してオーバーロードを自分で指定する、よりタイプ セーフなソリューションについては、jam40jeff の回答を参照してください。DateTimeBinaryWriter

于 2013-01-02T22:46:55.787 に答える
3

dynamicそれが最善の方法であることに同意しません。ここでの問題は、呼び出し元が処理可能な型Tを渡すことを保証する必要があることですBinaryWriter.Write()。を制約することによってこれを保証できる共通のクラスまたはインターフェースがないためT、これを行う最善の方法は、次のように呼び出し元に「負担を渡す」ことです。

private static void WriteToDisk<T>(string fileName, T[] vector, Action<BinaryWriter, T> callWrite)
{
    using (var stream = new FileStream(fileName, FileMode.Create))
    {
        using (var writer = new BinaryWriter(stream))
        {
            foreach (T v in vector)
                callWrite(writer, v);
            writer.Close();
        }
    }
}

これは次のように呼ばれます。

WriteToDisk("filename", new int[0], (w, o) => w.Write(o)); // compiles
WriteToDisk("filename", new string[0], (w, o) => w.Write(o)); // compiles
WriteToDisk("filename", new DateTime[0], (w, o) => w.Write(o)); // doesn't compile (as desired)

もちろん、既知の型のセットが少ない場合は、「便利なメソッド」を作成できます。

private static void WriteToDisk(string fileName, int[] vector)
{
    WriteToDisk(fileName, vector, (w, o) => w.Write(o));
}

private static void WriteToDisk(string fileName, string[] vector)
{
    WriteToDisk(fileName, vector, (w, o) => w.Write(o));
}

そして今、あなたの呼び出しは単純です:

WriteToDisk("filename", new int[0]);
WriteToDisk("filename", new string[0]);

コードが少し増えますが、コンパイル時の型の安全性と速度が大幅に向上します。

于 2013-01-03T04:58:51.547 に答える
0

次のように変更できます。

private static void WriteToDisk<T>(string fileName, T[] vector) where T : struct, IComparable,IComparable<T>

配列の型を数値型として保持したい場合。

于 2013-01-02T22:46:51.937 に答える