MrClan
MrClan

Reputation: 6780

How to access an already defined property of an anonymous linq object?

I've an answers dictionary object, ans and a LINQ query like this:

ans = new Dictionary<string,string>();
ans = LoadAnswers();

var milestones = LoadMilestones(session).Select(
                    m => new
                    {
                        milestoneid = GetSafeValue(m.Attribute("id").Value),
                        duedate = GetSafeValue(m.XPathValue("duedate")),
                        answer = ans[milestoneid]
                    }).ToArray()

Inside my milestones object, I've a property answer where I want to populate the data from ans object using milestoneid which is an already defined property. But this code won't compile, with error squiggly saying that type x does not contain a definition for milestoneid.

Since, GetSafeValue() is a huge method, I don't want to use it again to populate the answer property.

Q1) How can I use the milestoneid property for my answer ?

Q2) Also, I want to use ans.TrygetValue() to avoid null exceptions within that query. How to do that ?

Thanks.

Upvotes: 1

Views: 219

Answers (3)

StuartLC
StuartLC

Reputation: 107237

You could repeat the GetSafeValue(m.Attribute("id").Value) on the indexer when deriving answer (which isn't DRY), or instead, do a second projection to add fields derived from the initial projection:

var milestones = LoadMilestones(session)
                .Select(m => new
                {
                    milestoneid = GetSafeValue(m.Attribute("id").Value),
                    duedate = GetSafeValue(m.XPathValue("duedate")),
                })
                .Select(x => new 
                {
                   x.milestoneid,
                   x.duedate,
                   answer = ans[x.milestoneid]
                })
                .ToArray();

(neouser99's single-pass extended lambda answer is better, IMO)

Also, I'm not sure if this is actual code, but note that the below initialization is redundant

var ans = new Dictionary<string,string>();
ans = LoadAnswers();

Is reducable to just:

var ans = LoadAnswers();

Upvotes: 2

neouser99
neouser99

Reputation: 1827

You are not allowed to use a variable that's being assigned to the anon object you are returning. Meaning, milestoneid is a property of the new object, not a local variable. You could do this: ans[GetSafeValue(m.Attribute("id").Value)]. That is adding some unfortunate duplication though, I would recommend something more like this:

var milestones = LoadMilestones(session).Select(
                m => {
                    var id = GetSafeValue(m.Attribute("id").Value);
                    return new
                    {
                        milestoneid = id,
                        duedate = GetSafeValue(m.XPathValue("duedate")),
                        answer = loadStudentResponse ? null : ans[id]]
                    };
                }).ToArray()

As for the second question, TryGetValue returns a bool, and has an out param.

object answer; // the type should be whatever you are expecting.
ans.TryGetValue(id, out answer);

Maybe something like:

var milestones = LoadMilestones(session).Select(
                m => {
                    var id = GetSafeValue(m.Attribute("id").Value);

                    object answer; // the type should be whatever you are expecting.
                    ans.TryGetValue(id, out answer);

                    return new
                    {
                        milestoneid = id,
                        duedate = GetSafeValue(m.XPathValue("duedate")),
                        answer = answer
                    };
                }).ToArray()

Upvotes: 3

Eris
Eris

Reputation: 7638

The expression after the => can be a full fledged anonymous method that returns the new type. Hence you can hoist the values like so:

m => {
    var id = GetSafeValue(m.Attribute("id").Value);
    string answer;
    return new {
        milestoneid = id,
        duedate = GetSafeValue(m.XPathValue("duedate")),
        answer = ans.TryGetValue(id, out answer) ? answer : null
    }
}

Upvotes: 3

Related Questions