bob.mazzo
bob.mazzo

Reputation: 5627

Linq select query, how to append results to object of a class

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?

Upvotes: 1

Views: 2415

Answers (2)

code4life
code4life

Reputation: 15794

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);
}

Upvotes: 3

Ian
Ian

Reputation: 30813

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);
}

Upvotes: 1

Related Questions