2017-09-26 8 views
-1

次のネストされたループを条件付きでより読みやすいLINQステートメントに変換しようとしています。ネストされたループをLINQに変換する際の問題

IEnumerable<PropertyInfo> testClassPageObjects = FindPageObjects(); 
T newControl = default(T); 

Parallel.ForEach(testClassPageObjects, (pageObject,state) => 
{    
    Type pageObjectType = pageObject.PropertyType; 
    var pageObjectControls = pageObjectType.GetFields(); 

    foreach (var control in pageObjectControls.Where(control => control.FieldType == typeof(T))) 
    { 
     if (control.Name == fieldNameNoSpaces) 
     { 
      var findsByAttribute = (FindsByAttribute) control.GetCustomAttribute(typeof(FindsByAttribute)); 
      newControl = (T) control 
       .FieldType 
       .GetConstructor(new[] {typeof(IWebDriver), typeof(By)}) 
       .Invoke(new object[] {driver, findsByAttribute.Locator}); 

      state.Break(); 
     } 
    }    
}); 

可能であれば、LINQ文の前にあるすべてのif文が必要です。ステートメントは、最初の一致を返す必要があります。この場合、Parallel.ForEachとforeachを使用する必要はありません。

多くのありがとう、

+1

'&& control.Name == fieldNameNoSpaces'を' Where() '条件に追加することから始めることができます。私はあなたがなぜ半分の条件を1つの場所に、残りの条件を別の場所に持つのか分かりません。 – itsme86

+0

何を試しましたか?これはアウトソーシングサイトではありません* – barakcaf

答えて

1

これは次のようになります。これが正直に読みやすくなっているかどうかはわかりません。

T control = FindPageObjects 
      .SelectMany 
       (
        pageObject => 
        pageObject.PropertyType.GetFields() 
       ) 
      .OfType<T>() 
      .Where 
       (
        control => 
        control.FieldType == typeof(T) && 
        control.Name == fieldNameNoSpaces 
       ) 
      .Select 
       ( 
        selectedControl => 
        selectedControl.FieldType 
        .GetConstructor(new[] { typeof(IWebDriver), typeof(By)}) 
        .Invoke 
         (
          new object[] 
          { 
           driver, 
           ((FindsByAttribute)(selectedControl.GetCustomAttribute(typeof(FindsByAttribute)))).Locator 
          } 
         ) 
       ) 
      .OfType<T>() 
      .FirstOrDefault(); 

説明:

SelectMany OfTypeは必ずあなただけのタイプのコントロールを見ている可能

(ページオブジェクト内のコントロール)を使用すると、セット内のセットを反復処理することができますTを後でキャストする必要がなくなります。

ここで、はFieldTypeとNameをチェックします。

選択は、リフレクションを使用してコントロールのFieldTypeに基づいて新しいTをインスタンス化します。

OfType

FirstOrDefaultは、LINQは、それが見つかった最初のレコードのためにこれを実行することを意味しますT.に、コンストラクタ呼び出しの結果をキャストする2番目の時間が必要であり、そうでない場合それが何かを見つけるだけでnullを返します。これは元のコードのBreakに相当します。

ちなみに、並列化が必要な場合は、AsParallelを単に追加することができますが、どれだけ改善が得られるかはわかりません。

+0

ありがとうございます。私はあなたの提案のようにLINQの全体のアクションを実行することに終わっていませんでしたが、必要なものを私に提供しました。 – Konzy262

+0

私は通常、このような文を1つのステートメントに書きませんが、それは楽しいチャレンジと思っていました。プロダクションコードの正しいアプローチではないかもしれません。 –

関連する問題