3

タイトルに警告を表示する次のコードがあります。私は以前にこのようなことをしたことがあると確信していますが、警告は出ませんでした。それらの投稿について2つお聞きしたいのですが。1)ここで何が問題を引き起こすでしょうか?2)修正する必要がありますか?

私が尋ねる理由は、この警告が問題を引き起こしていないことは明らかであるため、このコードは正常に機能するためです。私は自分のコードに警告などを含めることに耐えられないので、これに対する解決策を望んでいますが、この警告が発生する理由と、それが何らかの形で有害であるかどうかも知りたいです。

コード:

 public class AttributeType
 {
      private string m_attributeNameField;

      public string AttributeName
      {
          get { return m_attributeNameField; }
          set { m_attributeNameField = value; }
      }
 }

 private StandardResponseType ValidateAttributes(string featureType, IEnumerable<AttributeType> attributeList, string userCategory)
 {
       StandardResponseType standardResponse = 
       new StandardResponseType(DateTime.Now.ToString(CultureInfo.InvariantCulture), "RWOL_UTILS.Get_Item_Attributes", "", "OK");

        if (attributeList.Any())
        {
            foreach (AttributeType attribute in attributeList)
            {
                if (attribute.AttributeName == null) continue;
                {
                    //do stuff
                }
            }
        }
        else
        {
            standardResponse.Message = "Error: No attributes passed in the list. ValidateAttributes().";
            standardResponse.ResponseCode = "FAIL";

            return standardResponse;
        }
}

編集:メソッドにはさらに多くのコードがありますが、この問題とは関係ありません。

更新:これを機能させるには、次のコードを追加する必要がありました。これを追加する方が効率的なのはなぜですか?新しいリストを数えて読む必要がある場合、それを行うことと元のアイテムでそれを行うことの違いは何ですか?リストは一度だけ渡されます。リストがメソッド内に入力されていても、そうでない場合は、この問題を理解できました。すでに記入済みで渡されます。

List<AttributeType> newlist = attributeList.ToList();

if (newlist.Count() != 0)
{
    foreach (AttributeType attribute in newlist)
............
4

8 に答える 8

6

ただ取り除くif; 無駄だ。

警告はResharperからのものであり、attributeList列挙するのに費用がかかる場合、コードが遅くなることを警告しています。Any()(1回と2回目を列挙するためforeach

于 2012-04-23T12:49:08.887 に答える
3

考えられる問題は、どこIEnumerableから来たかによって異なります。一部のデータソースでは、単一の列挙のみが許可されている場合や、(データベースクエリなど)コストがかかる場合があります。これは、によってすでに開始されていattributeList.Any()ます。

Any()に要素がない場合、ループは実行されないため、チェックを削除するだけでIEnumerable済みます(例が全体像を示しており、チェックに依存する他のロジックがないと仮定します)。

編集:編集した質問に基づいて、チェックを削除することはできません。ただし、を使用attributeList.ToArray()して配列に変換IEnumerableし、それを操作して警告を取り除くことができます。

于 2012-04-23T12:50:51.283 に答える
1

ある種の推測attributeListです。sとは異なり、オブジェクトは必ずしもメモリ内のオブジェクトのリストではなく、反復するたびにDBにクエリを実行する複雑なロジックにバインドされる場合があります。C#のコマンドを使用すると、すべての反復にバインドされたロジックを持つを返すこともできます。IEnumerable<>IEnumerableListyield returnIEnumerable

この動作のため、警告は、属性を複数回反復している可能性があることを示しています。これは、コストがかかる可能性のある操作です。の間にAny()1回、およびの間に1回foreach。この場合は不要ですが、一般に、またはをAny()呼び出すことでこの警告を回避できます。したがって、列挙を1回実行し、結果を明示的に割り当てられたリスト/配列に格納します。これで、パフォーマンスに影響を与えることなく、何度も何度も確認できます。ToList()ToArray()IEnumerable

于 2012-04-23T12:54:09.337 に答える
1

原因は、呼び出しattributeList.Any()が開始され、attributeList何かが見つかるとすぐにforループに入るというものです。次に、リストに対してforeachを実行します。これにより、リスト全体が再度トラバースされます。

.Any()空の列挙型に対してforeachを実行しても問題は発生せず、何も返されないため、実際にはここは必要ありません。

問題が発生する可能性があるのは、DBからデータをプルしていて、foreach内で列挙型をもう一度呼び出した場合です。これは、実行が延期されているため、2回目の呼び出しでは予期しない結果が返される可能性があるためです。

于 2012-04-23T12:50:54.783 に答える
0

.Any()をチェックする必要はありません。ここに修正されたコードがあります:

        bool empty = true;
        foreach (AttributeType attribute in attributeList) 
        { 
            empty = false;
            if (attribute.AttributeName == null) continue; 
            { 
                //do stuff 
            } 
        } 
        if (empty)
        {
          {  
              standardResponse.Message = "Error: No attributes passed in the list.       ValidateAttributes().";  
              standardResponse.ResponseCode = "FAIL";  

              return standardResponse;  
          }  
        }

.Any()をチェックすると列挙が発生する可能性があるため、警告が表示されます=>最初の列挙 "Any"は空かどうかをチェックし、2番目の列挙は"foreach"です。

attributeListのタイプで許可されている場合は、CountまたはLengthを確認できます。

    if (attributeList.Count != 0)         
    {         
        foreach (AttributeType attribute in attributeList)         
        {         
            if (attribute.AttributeName == null) continue;         
            {         
                //do stuff         
            }         
        }         
    }         
    else         
    {         
        standardResponse.Message = "Error: No attributes passed in the list. ValidateAttributes().";         
        standardResponse.ResponseCode = "FAIL";         

        return standardResponse;         
    } 
于 2012-04-23T12:49:53.817 に答える
0

いいえ、解決する必要はありません。ただし、if (attributeList.Any())がない場合は、else完全に削除できます。これにより、警告が削除されます。実際、コードサンプルは次のように置き換えることができます。

foreach (AttributeType attribute in attributeList.OfType<AttributeType>())
{
    // do stuff
}
于 2012-04-23T12:50:42.263 に答える
0

私はあなたにこれをさせることができました、それはよりきれいです:

しかし、とにかく、.Any()を呼び出すと、最初の項目を繰り返すだけなので、それほど悪くはありません。

この方法は、バックグラウンドでは少し醜いですが、より読みやすくなっています(それでも効率的です)。

        bool any;

        foreach (var i in Enumerable.Range(0, 100).Loop(out any))
        {
            // Do loop logic
        }

        if (!any)
        {
            // Handle empty IEnumerable
        }

どのように?!:

public static class Ex
{
    public static IEnumerable<T> Loop<T>(this IEnumerable<T> source, out bool any)
    {
        var b = true;

        var enumerable = source.Loop(() => { b = false; });

        any = b;

        return enumerable;
    }

    private static IEnumerable<T> Loop<T>(this IEnumerable<T> source, Action anySetter)
    {
        var enumerator = source.GetEnumerator();

        enumerator.Reset();

        if (!enumerator.MoveNext())
        {
            anySetter();
            yield break;
        }

        do
        {
            yield return enumerator.Current;
        } while (enumerator.MoveNext());
    }
}
于 2012-04-23T13:14:38.920 に答える
0

データセットへのクエリでこの正確な問題を検索したので、.Any()を追加して、選択の最後に.AsQueryable()を追加できることがわかり、foreachがそれで機能します。.AsQueryableは、汎用IEnumerableを汎用IQueryableに変換します。

于 2019-03-12T23:59:17.913 に答える