0

私はかなり奇妙な構造に直面しています。IEnumerable で返される Foo 型は、列挙が終了するとすぐにデータを失います。これは、データがすぐに失われるため、enumeration.First() を実行できないことを意味します。

ループは機能しますが、奇妙な要素が1つしか含まれないことがわかっているためです。

int Test(out int something)
    IEnumerable<Foo> enumeration = ...
    for (var foo in enumeration) {
        something = foo.GetSomething ();
        return foo.GetAnInt ();
    }
    something = 42;
    return 0;
}

私が考える別の方法は、Linq Select を悪用することですが、それも同様に恐ろしいことです。

この制限を回避する方法はありますか? 根本原因を修正することは明らかに優れていますが、この場合は困難です。

編集:これIEnumerable<IDataRecord>yield returned、トランザクション化された SQL データ リーダーからのものです。

public IEnumerable<IDataRecord> ExecuteReader (SqlCommand cmd)
{
    using (var con = GetConnection()) {
        con.Open ();

        using (var tr = con.BeginTransaction ()) {
            cmd.Connection = con;

            var reader = cmd.ExecuteReader ();
            while (reader.Read ()) {
                yield return reader;
            }

            tr.Commit ();
        }
    }
}
4

3 に答える 3

1

どうですか

int Test(out int something)
{
    IEnumerable<Foo> enumeration = ...
    var values = enumeration
        .Select(foo => new
                {
                    something = foo.GetSomething(),
                    anInt = foo.GetAnInt()
                })
        .FirstOrDefault();
    if (values != null)
    {
        something = values.something;
        return values.anInt;
    }
    else
    {
        something = 42;
        return 0;
    }
}

GetSomethingGetAnInt列挙内で呼び出されます。

于 2012-05-09T09:25:29.060 に答える
0

もう 1 つのアイデアは、メソッドの結果の型を IEnumerable から IEnumerator に変換することです。そうすれば、スコープ制御がはるかに簡単になり、単一の結果を返すのに (偽の) ループも必要ありません。

編集:問題全体をリファクタリングする方法を見つけたと思います。これにより、メソッドで以前に見つかったロジックを含む新しい使い捨てクラスを使用することで、最初の問題が回避されます。非常に読みやすく、コードも少なくて済みます。

public TransactedConnection GetConnection (string text)
{
    return new TransactedConnection (_ConnectionString, text);
}

public class TransactedConnection : IDisposable
{
    private readonly SQLiteCommand _Cmd;
    private readonly SQLiteConnection _Con;
    private readonly SQLiteTransaction _Tr;

    public TransactedConnection (string connection, string text)
    {
        _Cmd = new SQLiteCommand (text);
        _Con = new SQLiteConnection (connection);
        _Con.Open ();
        _Cmd.Connection = _Con;
        _Tr = _Con.BeginTransaction ();
    }

    public void Dispose ()
    {
        _Tr.Commit ();
        _Tr.Dispose ();
        _Con.Dispose ();
        _Cmd.Dispose ();
    }

    public SQLiteParameterCollection Parameters
    {
        get
        {
            return _Cmd.Parameters;
        }
    }

    public int ExecuteNonQuery ()
    {
        return _Cmd.ExecuteNonQuery ();
    }

    public object ExecuteScalar ()
    {
        return _Cmd.ExecuteScalar ();
    }

    public SQLiteDataReader ExecuteReader ()
    {
        return _Cmd.ExecuteReader ();
    }
}

public void Test (string match)
{
    var text = "SELECT * FROM Data WHERE foo=@bar;";

    using (var cmd = GetConnection (text)) {
        cmd.Parameters.Add ("@bar", DbType.String).Value = match;

        using (var reader = cmd.ExecuteReader ()) {
            while (reader.Read ()) {
                Console.WriteLine (reader["foo"]);
            }
        }
    }
}
于 2012-05-09T13:34:26.757 に答える