3

メソッド チェーンを使用して何かを記述するケースはいくつかありますが (特に、foo.Where(..).ToArray() のような 1 つまたは 2 つのメソッドの場合)、多くの場合、LINQ クエリ内包構文を好みます。代わりに(仕様の「クエリ式」)、次のようになります。

var query =
    from filePath in Directory.GetFiles(directoryPath)
    let fileName = Path.GetFileName(filePath)
    let baseFileName = fileName.Split(' ', '_').First()
    group filePath by baseFileName into fileGroup
    select new
    {
        BaseFileName = fileGroup.Key,
        Count = fileGroup.Count(),
    };

それらのかなり大きなチャンクでは、結果の IEnumerable を取り、それをデータ構造 (配列、リストなど) に熱心にロードする必要があります。これは通常、次のいずれかを意味します。

  1. var queryResult = query.ToArray(); のような別のローカル変数を追加します。また

  2. クエリを括弧で囲み、ToArray (または ToList など) にタグ付けします。

var query = (
    from filePath in Directory.GetFiles(directoryPath)
    let fileName = Path.GetFileName(filePath)
    let baseFileName = fileName.Split(' ', '_').First()
    group filePath by baseFileName into fileGroup
    select new
    {
        BaseFileName = fileGroup.Key,
        Count = fileGroup.Count(),
    }
).ToArray();

他の人がどのオプションを使用しているか、または 2) いくつかの追加の「コンテキスト キーワード」を追加することが実行可能であると考えることができるオプションを見つけようとしています。あたかもLINQキーワードが「ネイティブに」拡張可能であるかのように:)

おそらく、これはある種の前処理 (C# のこの領域に何があるかはわかりません) か、Nemerleのようなものに使用されるコンパイラーの変更(オプションになると思いますが、確かではありませんか? )。私は Roslyn が何をサポートするか、またはサポートするかについてまだ十分に知らないので、誰かがこのように C# を「拡張」できるかどうかを知っている人がいたら、声をかけてください!

私が最も使用する可能性が高いもの(他にもたくさんあると確信していますが、アイデアを理解するため/私が望んでいること):

ascount - Count() に変換

int zFileCount =
    from filePath in Directory.GetFiles(directoryPath)
    where filePath.StartsWith("z")
    select filePath ascount;

これは、次のように「変換」されます (最終結果がそうである限り、パスが何であるかは関係ありません)。

int zFileCount = (
    from filePath in Directory.GetFiles(directoryPath)
    where filePath.StartsWith("z")
    select filePath
).Count();

同様に:

  • asarray - ToArray() に変換します
  • aslist - ToList() に変換

(明らかに、First()、Single()、Any() などを続けることもできますが、質問の範囲を抑えるようにしてください:)

パラメーターを渡す必要のない拡張メソッドにのみ関心があります。私は、(たとえば) ToDictionary や ToLookup でこの種のことをしようとしているわけではありません。:)

つまり、要約すると:

  • 「ascount」、「aslist」、および「asarray」をlinqクエリ式に追加したい
  • これがすでに解決されているかどうかはわかりません
  • Nemerleがこれに適しているかどうかはわかりません
  • Roslyn の話がこの種の使用をサポートするかどうかはわかりません
4

3 に答える 3

13

あなたの質問への答えではなく、あなたのデザインに関するいくつかの考えです。そのような機能を C# 4 に追加することを強く検討しましたが、時間とリソースが利用できなかったため、削除しました。

お気づきのように、クエリ内包構文の問題は、「流れるような」構文と「内包」構文を混在させるのが見苦しいことです。あなたの顧客がロンドンで何種類の苗字を持っているか知りたいのですが、括弧を付けてこの醜いものを書くことになります:

d = (from c in customers 
     where c.City == "London" 
     select c.LastName)
    .Distinct()
    .Count();

うん。

理解構文に新しいコンテキスト キーワードを追加することを検討しました。引数のために、キーワードが「with」であるとしましょう。次に、次のように言うことができます。

d = from c in customers 
    where c.City == "London" 
    select c.LastName
    with Distinct() 
    with Count();

そして、クエリ理解リライターはそれを適切な流暢な構文に書き換えます。

私はこの機能が本当に気に入っていますが、C# 4 または 5 には採用されませんでした。この言語の仮想的な将来のバージョンに組み込むとよいでしょう。

いつものように、決して存在しないかもしれない未発表の製品の架空の機能についての Eric の考えは、娯楽目的のためだけのものです。

于 2012-01-08T15:58:23.423 に答える
2

他の人が言ったように、Roslynはおそらくあなたが思っているものではありません。C#の拡張には使用できません。

次のコードはすべて、ブレインストーミングを増やし、推奨事項を減らすことを検討する必要があります。これにより、LINQの予期しない動作が変わります。そのようなものを使用する前に、真剣に考える必要があります。

selectこれを解決する1つの方法は、次のように句を変更することです。

int count = from i in Enumerable.Range(0, 10)
            where i % 2 == 0
            select new Count();

実装は次のようになります。

public  class Count
{}

public static class LinqExtensions
{
    public static int Select<T>(
        this IEnumerable<T> source, Func<T, Count> selector)
    {
        return source.Count();
    }
}

にないものを入れるとCountselect通常どおりに動作します。

配列に対して同様のことを行うと、select配列とそこに必要なアイテムのセレクターの両方を指定する必要があるため、より多くの作業が必要になりますが、それは実行可能です。または、2つのを使用することもできます。1selectつはアイテムを選択し、もう1つは配列が必要であることを示します。

別のオプション(Kevinの提案と同様)は、次のようAsCount()に使用できる拡張メソッドを使用することです。

int count = from i in Enumerable.Range(0, 10).AsCount()
            where i % 2 == 0
            select i;

次のように実装できます。

public static class LinqExtensions
{
    public static Countable<T> AsCount<T>(this IEnumerable<T> source)
    {
        return new Countable<T>(source);
    }
}

public class Countable<T>
{
    private readonly IEnumerable<T> m_source;

    public Countable(IEnumerable<T> source)
    {
        m_source = source;
    }

    public Countable<T> Where(Func<T, bool> predicate)
    {
        return new Countable<T>(m_source.Where(predicate));
    }

    public Countable<TResult> Select<TResult>(Func<T, TResult> selector)
    {
        return new Countable<TResult>(m_source.Select(selector));
    }

    // other LINQ methods

    public static implicit operator int(Countable<T> countable)
    {
        return countable.m_source.Count();
    }
}

私はそれがこのように好きかどうかわかりません。特に暗黙のキャストは違和感がありますが、他に方法はないと思います。

于 2012-01-08T03:26:11.557 に答える