1

NavigationTitle、NavigationUrl、および IsCurrent プロパティを持つ単なる軽量クラスである Breadcrumb 型の IList があります。Web サーバーにキャッシュされます。以下のコードを使用して、IsCurrent が true に設定されている最初のパンくずリストまで、現在のパンくずリストを構築するメソッドがあります。それは非常に醜く、間違いなく迅速なダートバッグウィリーソリューションですが、私は興味がありました.これはLINQに簡単にリファクタリングできますか?

IList<Breadcrumb> crumbs = new List<Breadcrumb>();
bool foundCurrent = false;
for (int a = 0; a < cachedCrumbs.Count; a++)
{
    crumbs.Add(crumbs[a]);
    if (foundCurrent)
    {
      break;
    }
    foundCurrent = (crumbs[a + 1] != null && ((Breadcrumb)crumbs[a + 1]).IsCurrent);
}
4

5 に答える 5

5

考えながら入力しているので、単なる答えだけでなく一連の思考も表示されます。

  • あなたのソースは単に cachedCrumbs です
  • IsCurrentが設定されている最初のクラムを追加したいが、その後は何も追加しない
  • TakeWhile は道のりのように聞こえますが、「以前の値に IsCurrent があった」ことを取得するのは少し面倒です
  • クロージャーを使用して、最後の値に IsCurrent が設定されているかどうかを判断する変数を効果的に保持できます
  • 続行するかどうかの作業から TakeWhile を分離しておくために、多少「操作なし」の選択を行うことができます。

したがって、最終的には次のようになります。

bool foundCurrent = false;

var crumbs = cachedCrumbs.TakeWhile(crumb => !foundCurrent)
                         .Select(crumb => { 
                                 foundCurrent = crumb == null || !crumb.IsCurrent; 
                                 return crumb; });

私はこれを試していませんが、うまくいくはずだと思います...もっと簡単な方法があるかもしれません。

編集:この場合、実際にはまっすぐな foreach ループの方が簡単だと思います。そうは言っても、TakeWhile のように機能する別の拡張メソッドを作成することもできますが、条件が失敗する原因となった要素も返されます。次に、次のように簡単になります。

var crumbs = cachedCrumbs.NewMethod(crumb => crumb == null || !crumb.IsCurrent);

(現時点では、このメソッドの適切な名前が思い浮かびませんNewMethod!)

于 2008-10-25T17:08:18.813 に答える
1

James Curran に基づく別の回答 - これは foreach ステートメントを使用して確実に改善できます。

IList<Breadcrumb> crumbs = new List<BreadCrumb>();
foreach (Breadcrumb crumb in cachedCrumbs)
{
    crumbs.Add(crumb);
    if (crumb != null && crumb.IsCurrent)
    {
        break;
    }
}
于 2008-10-25T17:10:23.617 に答える
1

どうですか...

// find the current item
var currentItem = cachedCrumbs.First(c => c.IsCurrent);
var currentIdx = cachedCrumbs.IndexOf(currentItem);

// get all items upto current item
var crumbs = cachedCrumbs.Take(currentIdx + 2);

そして、これを TakeUpto メソッドに変換して、指定した述語に一致するものまですべてのアイテムを取ることができます。

どうですか:

public static IEnumerable<T> TakeUpto<T>(this IList<T> theList, Func<T, bool> predicate)
{
    var targetItem = theList.First(predicate);
    var targetIdx = theList.IndexOf(targetItem);

    return theList.Take(targetIdx + 2);
}

次に、次のように使用できます。

var crumbs = cachedCrumbs.TakeUpto(c => c.IsCurrent);

もっときれいに!

null と off-by-one のケースと IList/IEnumerable の違いをチェックしていませんが、アイデアは得られるはずです。

于 2008-10-25T17:45:29.317 に答える
1

まず、そのコードは機能しません。「crumbs」を使用した場所のいくつかは、「cachedCrumbs」を意味していると思います。その場合、コードは次のように削減できます。

IList<Breadcrumb> crumbs = new List<Breadcrumb>();
for (int a = 0; a < cachedCrumbs.Count; a++)
{
    crumbs.Add(cachedCrumbs[a]);
    if (cachedCrumbs[a] != null && cachedCrumbs[a].IsCurrent)
    {
          break;
    }
}
于 2008-10-25T17:06:56.523 に答える
1

この回答は、chakrit の TakeUpTo の代替実装です。

public static IEnumerable<T> TakeUpto<T>(this IEnumerable<T> theList, Func<T, bool> predicate)
{
    foreach (T element in theList)
    {
        yield return element;
        if (predicate(element))
        {
            break;
        }
    }
}

これはリストを 1 回だけ繰り返しますが、これはさまざまな場合に関連する可能性があります。(アップストリーム シーケンスが OrderBy 句の結果であるとします。正当な理由もなく結果を複数回並べ替える必要はありません。)

また、任意IEnumerable<T>のソースを使用できるため、より柔軟になります。

LINQ の優れた点の 1 つは、同じ目標を達成する方法が複数あることです。

于 2008-10-25T19:19:45.383 に答える