0

ICollection<string>のクラスのプロパティに追加する必要がありIEnumerableます。これが問題を説明する完全なプログラムです:

using System;
using System.Collections.Generic;
using System.Linq;

namespace CollectionAddingTest
{
    public class OppDocumentServiceResult
    {
        public OppDocumentServiceResult()
        {
            this.Reasons = new List<string>();
        }

        public Document Document { get; set; }

        public bool CanBeCompleted
        {
            get
            {
                return !Reasons.Any();
            }
        }

        public ICollection<string> Reasons { get; private set; }
    }

    public class Document
    {
        public virtual string Name { get; set; }
    }

    public class Program
    {
        private static void Main(string[] args)
        {
            var docnames = new List<string>(new[] {"test", "test2"});

            var oppDocResult = docnames
                .Select(docName
                        => new OppDocumentServiceResult
                               {
                                   Document = new Document { Name = docName }
                               });

            foreach (var result in oppDocResult)
            {
                result.Document.Name = "works?";
                result.Reasons.Add("does not stick");
                result.Reasons.Add("still does not stick");
            }

            foreach (var result in oppDocResult)
            {
                // doesn't write "works?"
                Console.WriteLine(result.Document.Name);

                foreach (var reason in result.Reasons)
                {
                    // doesn't even get here
                    Console.WriteLine("\t{0}", reason);
                }
            }
        }
    }
}

各OppDocumentServiceResultの参照Document.Name プロパティが機能するように設定されていると思いますか?また、各OppDocumentServiceResultには2つの理由が追加されている必要があります。しかし、どちらも起こっていません。

Reasonsプロパティの何が特別で、追加できないのですか?

4

5 に答える 5

2

Select問題は、新しいOppDocumentServiceResultオブジェクトをインスタンス化する最初の問題です。を追加するToListと、準備が整います。

var oppDocResult = docnames
    .Select(docName
            => new OppDocumentServiceResult
                   {
                       Document = new Document { Name = docName }
                   }).ToList();

Servyが指摘したように、私は私の答えにもう少し詳細を追加する必要がありましたが、ありがたいことに、 Tallmarisの答えに彼が残したコメントはそれを処理します。彼の回答では、Jon Skeetがその理由をさらに詳しく説明していますが、要約すると、「oppDocResultは、遅延実行を使用したLINQクエリの結果である」ということです。

于 2012-05-15T16:34:06.603 に答える
2

問題は、oppDocResult遅延実行を使用したLINQクエリの結果であるということです。

つまり、それを繰り返すたびに、クエリが実行され、新しい OppDocumentServiceResultオブジェクトが作成されます。コンストラクターに診断を入れるとOppDocumentServiceResult、それがわかります。

したがって、OppDocumentServiceResult最後に反復しているオブジェクトは、理由を追加したオブジェクトとは異なります。

ToList()ここで、呼び出しを追加すると、クエリが「プレーン」コレクション(a )に具体List<OppDocumentServiceResult>化されます。そのリストを反復するたびに、同じオブジェクトへの参照が返されます。したがって、最初に反復するときに理由を追加し、もう一度反復するときに理由を印刷すると、結果が得られます。探しています。

詳細については、このブログ投稿(「LINQ遅延実行」の多くの検索結果の中で)を参照してください。

于 2012-05-15T16:39:54.173 に答える
1

ForEach()に対して定義されているのは、に対して使用することはできList<T>ませICollection<T>

オプションが必要です:

((List<string>) Reasons).ForEach(...)

または

Reasons.ToList().ForEach(...)

それでも、私の好みのアプローチ

リソースを無駄にすることなくこれを自動化するのに役立つこの拡張機能を定義します。

public static class ICollectionExtensions
{
    public static void ForEach(this ICollection<T> collection, Action<T> action)
    {
        var list = collection as List<T>;
        if(list==null)
            collection.ToList().ForEach(action);
        else
            list.ForEach(action);
    }
}

今、私はForEach()に対して使用することができますICollection<T>

于 2012-05-15T15:54:34.733 に答える
1

このように修正され、IEnumerableを保持する代わりにListに変換されます。

var oppDocResult = docnames
        .Where(docName => !String.IsNullOrEmpty(docName))
        .Select(docName
            => new OppDocumentServiceResult
            {
                Document = docName
            }).ToList();

私は推測することしかできません(これは本当に暗闇の中でのショットです!)これの背後にある理由は、IEnumerableでは要素が実際の要素の「プロキシ」のようなものであるということですか?基本的に、Linqクエリによって定義されたEnumerableは、すべてのデータを取得するための「約束」のようなものです。したがって、反復するたびに、元のアイテムを取得しますか?それは、なぜ通常のプロパティがまだ固執するのかを説明していません...

だから、修正はありますが、私が恐れている説明はそうではありません...少なくとも私からではありません:(

于 2012-05-15T16:26:23.710 に答える
0

クラス内のコードを変更するだけです

public List<string> Reasons { get; private set; }
于 2012-05-15T16:02:47.150 に答える