Reputation: 5703
In VB, the following is a valid object initializer in which one member intializer references the value of another member that has previously been initialized.
new MyObject() with {.Property1="x", .Property2 = .Property1 + "y"}
If I try to do the same in C#
using
new MyObject() {Property1 = "x", Property2 = Property1 + "y"}
I get the error
The name 'Property1' does not exist in the current context.
It is a little surprising since there is a fair amount of parity between the two languages but perhaps this is one of those few differences.
Is there a way to do this in C#
? For those wondering what the specific use case may be, I am constructing a composite object structure using a fairly complex LINQ query.
IEnumerable<Question> query =
(from q in dtQuestions.AsEnumerable()
join a in dtAnswers.AsEnumerable() on q.Field<int>("question_type_id") equals a.Field<int>("question_type_id") into Group
select new Question()
{
Id = q.Field<int>("question_type_id"),
SequenceNumber = q.Field<int>("sequence_no"),
IsChild = q.Field<bool>("isChildQuestion"),
EktronContentKey = q.Field<string>("ektron_content_key"),
Text = q.Field<string>("description"),
QuestionKindId = q.Field<int>("question_kind_type_id"),
Answers = (from a2 in Group
select new Answer()
{
Id = a2.Field<int>("answer_type_id"),
SequenceNumber = a2.Field<int>("sequence_no"),
EktronContentKey = a2.Field<string>("ektron_content_key"),
Text = a2.Field<string>("description"),
IsSelected = a2.Field<bool>("isSelected"),
ImageKey = q.Field<int>("question_type_id") == 2 ? "" : (Id % 2 == 0 ? "heating-gas-modern.png" : "heating-gas-condensing.png"),
ChildQuestionIds =
(from r in dtAnswerChildQuestions.AsEnumerable()
where r.Field<int>("answer_type_id") == Id
select r.Field<int>("question_type_id")).ToArray()
}).ToArray(),
SelectedAnswerId = QuestionKindId == 1 ?
(from Answer a3 in Answers
where a3.IsSelected == true
select a3.Id).SingleOrDefault() :
0,
SelectedAnswerIds = QuestionKindId == 2 ?
(from Answer a4 in Answers
where a4.IsSelected == true
select a4.id).ToArray() :
new int() { }
}
);
The real problem to address in this is the reference to the Answers property in the LINQ expression used to assign values to SelectedAnswerId and SelectedAnswerIds. I may have to factor those two expressions out into their own standalone assignments.
Upvotes: 3
Views: 335
Reputation: 5703
I wound up having to resolve this by using a secondary for loop. The code was a bit too complicated to do with LET statements.
IEnumerable<Question> query =
(from q in dtQuestions.AsEnumerable()
join a in dtAnswers.AsEnumerable() on q.Field<int>("question_type_id") equals a.Field<int>("question_type_id") into Group
select new Question()
{
Id = q.Field<int>("question_type_id"),
SequenceNumber = q.Field<int>("sequence_no"),
IsChild = q.Field<bool>("isChildQuestion"),
EktronContentKey = q.Field<string>("ektron_content_key"),
Text = q.Field<string>("description"),
QuestionKindId = q.Field<int>("question_kind_type_id"),
Answers = new AnswerCollection((from a2 in Group
select new Answer()
{
Id = a2.Field<int>("answer_type_id"),
SequenceNumber = a2.Field<int>("sequence_no"),
EktronContentKey = a2.Field<string>("ektron_content_key"),
Text = a2.Field<string>("description"),
IsSelected = a2.Field<bool>("isSelected"),
ImageFileId = a2.Field<int?>("file_id"),
ChildQuestionIds =
new Collection<int>((from r in dtAnswerChildQuestions.AsEnumerable()
where r.Field<int>("answer_type_id") == a2.Field<int>("answer_type_id")
select r.Field<int>("question_type_id")).ToList())
}))
}
);
foreach (var question in query)
{
question.SelectedAnswerId = question.QuestionKindId == 1 ?
(from Answer a3 in question.Answers
where a3.IsSelected == true
select a3.Id).SingleOrDefault() :
0;
question.SelectedAnswerIds = question.QuestionKindId == 2 ?
new Collection<int>((from Answer a4 in question.Answers
where a4.IsSelected == true
select a4.Id).ToList()) :
new Collection<int>();
this.Add(question);
}
Upvotes: 0
Reputation: 31606
Referencing a property as such in C# is not possible. Since you have the "X" its obvious that the code can be written to use X.
Since this is Linq you may want to use a Let clause and create the business logic processing to process X and maybe even Y and then do the member initialization.
Upvotes: 4
Reputation: 3167
I'm not sure about getting access to Property1 in C# in the initializer, but since you've got the value for Property1 available, you could do the following, and hope the compiler optimizes it correctly:
new MyObject() {Property1 = "x", Property2 = "x" + "y"}
That would make for ugly code in your case, though, and you may be better off factoring those two expressions into their own standalone assignments.
Alternately, you could move some of the code into the Answers property setter so that if QuestionKindId is already set, then you can internally set the properties SelectedAnswerId and SelectedAnswerIds.
Upvotes: 1