2

間違いなく LINQ の初心者ですが、SQL と C# の経験が豊富で、LINQ でこれが可能かどうか疑問に思っています。もしそうなら、私はそれを他の場所で使うことができますが、これは良い出発点になると思いました(そして、いくつかのコードを簡素化/クリーンアップするのに役立ちます)。これはもっと一般化できますが、これは説明に役立つ実生活の良い例かもしれないと思いました.

簡単な背景: 私は、スケジューラを構築し、Spring.NET/DI、Fluent NHibernate、Quartz.NET を学習する個人的な学習プロジェクトを行っており、TDD に慣れようとしています。これまでにたくさんのことを学びました。

Quartz.NET IScheduler オブジェクトには、これらのプロパティ (1)/メソッド (2) (パブリックを想定) があります...

string[] JobGroupNames { get; }
string[] GetJobNames(string groupName)
Trigger[] GetTriggersOfJob(string jobName, string groupName)

トリガーの定義はただ...

class Trigger
{  
    string Name { get; }
}  

次のようなコンストラクターを持つリストを取得しようとしているクラスがあります(一度作成すると不変であるため)...

class QuartzJob
{
    public QuartzJob(Guid groupId, Guid jobId, IEnumerable<string> triggerNames)
}

現在、私はこのように処理しています...

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    List<QuartzJob> list = new List<QuartzJob>();

    foreach (string grp in scheduler.JobGroupNames)
    {
        foreach (string job in scheduler.GetJobNames(grp))
        {
            var triggerNames = scheduler
                .GetTriggersOfJob(job, grp)
                .ToList()
                .ConvertAll(t => t.Name);

            var qj = new QuartzJob(new Guid(grp), new Guid(job), triggerNames);
            list.Add(qj);
        }
    }    
    return list;
}

この方法はうまく機能しますが (少し遅くて複雑かもしれませんが)、これらの二重の foreach ループは私を悩ませます。

これは学習プロジェクトであるため、誰かにコードを書いてもらうのではなく (むしろ歓迎します)、LINQ がこのようなことを実行できるかどうかを確認しようとしているだけです。 ... クエリ値を使用してメソッドを呼び出し、それらの値を使用して別のクエリを作成します。もしそうなら、コードの他の場所にある複数の foreach ループの一部を減らすことができます。

ありがとう!

4

1 に答える 1

5

LINQ でこれを行うための鍵は、.Select があなたの友人であることを理解することです。私は子供です。Select を使用すると、そのいとこである SelectMany を使用して、配列をその場で変換できます。

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    IEnumerable<QuartzJob> jobs = scheduler.JobGroupNames.SelectMany(   // Using SelectMany because there is an IEnumerable<QuartzJob> for each group and we want to flatten that.
        groupName => scheduler.GetJobNames(groupName).Select(  // Returns an IEnumerable<QuartzJob> for each group name found.
            jobName => 
                // We're doing a lot in this new but essentially it creates a new QuartzJob for each jobName/groupName combo
                new QuartzJob(new Guid(groupName), new Guid(jobName),
                    scheduler.GetTriggersOfJob(jobName, groupName).Select(trigger => trigger.Name)  // This transforms the GetTriggersOfJob into an IEnumerable<string> for use in the constructor of QuartzJob
                    ))); 
    return new List<QuartzJob>(jobs);
}

または、インライン クエリ言語を好む場合は、もう少し読みやすく、次のようになります。

public IEnumerable<QuartzJob> GetQuartzInfo(IScheduler scheduler)
{
    IEnumerable<QuartzJob> jobs = from groupName in scheduler.JobGroupNames
                                  from jobName in scheduler.GetJobNames(groupName) // stacking the two froms is the equivalent of SelectMany because the first select is defaulted as the result of the second.
                                  select new QuartzJob(new Guid(groupName), new Guid(jobName),
                                      // this sub-select is to get just the IEnumerable<string> of trigger names needed for the constructor.
                                      (from trigger in scheduler.GetTriggersOfJob(jobName, groupName)
                                       select trigger.Name));
    return new List<QuartzJob>(jobs);
}
于 2009-11-24T00:38:43.590 に答える