1

In the c# code snipped below, instead of creating a new tradeContributions each time, I need to add to this IEnumerable collection.

I thought I would be able to execute tradeContributions.add() but the add() method is not available.

public static IEnumerable<TradeContribution> GetTradeContributions(uint portfolioId, List<uint> portfolioIdList, IEnumerable<DateTime> nodeDateList, int? whatIfBatchNumber = null)
        {

            // THIS IS THE ORIGINAL CODE
            IEnumerable<TradeContribution> tradeContributions = new List<TradeContribution> { };


tradeContributions = (from tc in xml.XPathSelectElement("body/portfolios/portfolio/contributions").Elements("tradeContribution")
   select new TradeContribution
   {
    SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
    TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
    TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
    ProductType = tc.Attribute("desc").Value,
    ProductDescription = tc.Attribute("desc").Value, // TODO: In future could lookup the description in a reference data cache
    Contribution = decimal.Parse(tc.Attribute("contribution").Value)
   })
   .OrderByDescending(x => x.Contribution);



    // ... code omitted for brevity

    // THIS IS MY NEW CODE TO HANDLE THE NEW REQUIREMENTS
    foreach (XElement pfElem in xml.XPathSelectElements("body/portfolios/portfolio"))
    {
        tradeContributions = (from tc in pfElem.XPathSelectElement("contributions").Elements("tradeContribution")
       select new TradeContribution
       {
        SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
        TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
        TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
        ProductType = tc.Attribute("desc").Value,
        ProductDescription = tc.Attribute("desc").Value,
        Contribution = decimal.Parse(tc.Attribute("contribution").Value)
       }
        );
    }
 
          return tradeContributions;
        }
    }

How can I add each new tradeContribution to my collection?

bob.mazzo
  • 5,183
  • 23
  • 80
  • 149
  • 2
    Possible duplicate of [How can I add an item to a IEnumerable collection?](http://stackoverflow.com/questions/1210295/how-can-i-add-an-item-to-a-ienumerablet-collection) – Steve Feb 22 '16 at 01:09
  • 1
    Any reason why `tradeContributions` are `IEnumerable`? – code4life Feb 22 '16 at 01:46

2 Answers2

3

I have an issue with this line here:

IEnumerable<TradeContribution> tradeContributions = new List<TradeContribution> { };

This is a local variable... so why are we locking it down to a limited contract, as an IEnumerable? It's really a List<T>, so just declare it like:

var  tradeContributions = new List<TradeContribution> { };

Once you've done that, all you need to do is change your code block within the foreach to:

tradeContributions.AddRange((from tc in pfElem.XPathSelectElement("contributions").Elements("tradeContribution")
  select new TradeContribution
  {
      SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
      TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
      TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
      ProductType = tc.Attribute("desc").Value,
      ProductDescription = tc.Attribute("desc").Value,
      Contribution = decimal.Parse(tc.Attribute("contribution").Value)
  }));

Basically, IMHO, by using the IEnumerable, you're creating an artificial limitation that might have made sense if there was some logical boundary being crossed. But there isn't... so you shouldn't.

UPDATE:

OK, now that I see the code for the entire method, I can understand (sort of) why the IEnumerable declaration was made. I kind of think that the variable is redundant. You just need to Concat() the two LINQs together and return the result, IMHO.

Sort of like this:

public static IEnumerable<TradeContribution> GetTradeContributions(uint portfolioId, List<uint> portfolioIdList, IEnumerable<DateTime> nodeDateList, int? whatIfBatchNumber = null)
{
    var originalItems = (from tc in xml.XPathSelectElement("body/portfolios/portfolio/contributions").Elements("tradeContribution")
    select new TradeContribution
    {
      SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
      TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
      TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
      ProductType = tc.Attribute("desc").Value,
      ProductDescription = tc.Attribute("desc").Value, // TODO: In future could lookup the description in a reference data cache
      Contribution = decimal.Parse(tc.Attribute("contribution").Value)
  })
  .OrderByDescending(x => x.Contribution);



// ... code omitted for brevity

// THIS IS MY NEW CODE TO HANDLE THE NEW REQUIREMENTS
    var additionalItems = xml.XPathSelectElements("body/portfolios/portfolio")
        .SelectMany(pfElem => 
        {
            (from tc in pfElem.XPathSelectElement("contributions").Elements("tradeContribution")
          select new TradeContribution
          {
          SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
          TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
          TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
          ProductType = tc.Attribute("desc").Value,
          ProductDescription = tc.Attribute("desc").Value,
          Contribution = decimal.Parse(tc.Attribute("contribution").Value)
          }
        });

    return originalItems.Concat(additionalItems);
}
code4life
  • 15,655
  • 7
  • 50
  • 82
  • right, I don't understand either why the previous dev created `tradeContributions` as IEnumerable. So I've updated my original post to show the code block that I was dealing with PRIOR to adding my new `foreach` section. – bob.mazzo Feb 22 '16 at 02:21
  • in addition, if I try to change the original tradeContributions object to `new List{}`, then the original `select new` section at the top will cause some kind of exception. It's a bit confusing to me, so I will go with a new var for the `List<>` idea you gave me. thanks. – bob.mazzo Feb 22 '16 at 02:23
1

Since you already create the IEnumerable by new List

IEnumerable<TradeContribution> tradeContributions = new List<TradeContribution> { };

Why not declaring it altogether as List to simplify your problem?

List<TradeContribution> tradeContributions = new List<TradeContribution> { };

Then you can use it like this with the help of already available AddRange (and Add) method in the List:

foreach (XElement pfElem in xml.XPathSelectElements("body/portfolios/portfolio"))
{
    var temp = (from tc in pfElem.XPathSelectElement("contributions").Elements("tradeContribution")
      select new TradeContribution
      {
          SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
          TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
          TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
          ProductType = tc.Attribute("desc").Value,
          ProductDescription = tc.Attribute("desc").Value,
          Contribution = decimal.Parse(tc.Attribute("contribution").Value)
      }
    );
    tradeContributions.AddRange(temp.ToArray()); //then add the results to the List
}

Else, if you want the query to be added to a IEnumerable then you can also use Concat.

foreach (XElement pfElem in xml.XPathSelectElements("body/portfolios/portfolio"))
{
    var temp = (from tc in pfElem.XPathSelectElement("contributions").Elements("tradeContribution")
      select new TradeContribution
      {
          SysId = tc.Attribute("sysId") == null ? 0 : int.Parse(tc.Attribute("sysId").Value),
          TradeContextId = tc.Attribute("contextId") == null ? 0 : int.Parse(tc.Attribute("contextId").Value),
          TradeId = tc.Attribute("tradeId") == null ? "" : tc.Attribute("tradeId").Value,
          ProductType = tc.Attribute("desc").Value,
          ProductDescription = tc.Attribute("desc").Value,
          Contribution = decimal.Parse(tc.Attribute("contribution").Value)
      }
    );
    tradeContributions = tradeContributions.Concat(temp);
}
Ian
  • 30,182
  • 19
  • 69
  • 107