Question

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.

Était-ce utile?

La solution 3

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

Autres conseils

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.

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top