First item in select new not available in foreach

Dec 20, 2007 at 7:58 PM
In the following code, if I remove the string.Empty 'place holder' and move p.ID to the front of the list, I get a compile error when referencing p.ID in the string.Format statement later on:

AnonymousType#1' does not contain a definition for 'ID' and no extension method 'ID' accepting a first argument of type 'AnonymousType#1' could be found (are you missing a using directive or an assembly reference?

static void Main(string[] args)
{
var ctx = new RemoverSharePointDataContext();
ctx.Log = Console.Out;

// get some information about the discussion board
var res = from p in ctx.WGDiscussionTopics
where p.ID > 0
orderby p.DateCreated descending
select new { WgDiscussionTopic = string.Empty, p.EMailSender, p.ID, p.Subject, p.DateCreated };

foreach (var p in res)
{
string message = string.Format("ID = {0}, Subject = {1}, Date Created = {2}"
, p.ID, p.Subject , p.DateCreated);
Console.WriteLine(message);
}

Console.WriteLine("Press Enter when finished.");
Console.ReadLine();
}
Coordinator
Feb 7, 2008 at 6:58 AM
Thanks for your comment; sorry for the delay it took to answer. LINQ to SharePoint doesn't interfere with the front-end language compiler in any way, so this seems to be a pure C# 3.0 question. The code you posted should compile (assuming the list entity has the referenced properties), moving the order of property initializers in the anonymous type definition shouldn't change that. The conceptual problem might be the reuse of "p" as a variable name: once for the dummy inside the expression and once for the foreach loop variable. Inside the loop, p is of type "whatever the projection (select clause) of res produces". Essentailly your code is rewritten as:

var res = from p in ctx.WGDiscussionTopics
where p.ID > 0
orderby p.DateCreated descending
select new { WgDiscussionTopic = string.Empty, EMailSender = p.EMailSender, ID = p.ID, Subject = p.Subject, DateCreated = p.DateCreated };

meaning the type inside the loop has properties WgDiscussionTopic, EMailSender, ID, Subject and DateCreated. If you change it like this:

var res = from p in ctx.WGDiscussionTopics
where p.ID > 0
orderby p.DateCreated descending
select new { WgDiscussionTopic = p.ID, EMailSender = p.EMailSender, Subject = p.Subject, DateCreated = p.DateCreated };

the projected type has properties WgDiscussionTopic, EMailSender, Subject and DateCreated (no ID), so you loop code needs to be:

foreach (var p in res)
{
string message = string.Format("ID = {0}, Subject = {1}, Date Created = {2}"
, p.WgDiscussionTopic, p.Subject , p.DateCreated);
Console.WriteLine(message);
}

in that case. My advice: avoid reuse of dummy variable names outside the query (inside the same method block scope) to avoid confusion, although it's technically no problem (the reason for that being that the dummy 'p' inside the query expression becomes a local dummy variable for the lambda expressions under the covers).

Hope this helps,
-Bart