guo
guo

Reputation: 10229

c#: IEnumerable not work outside for loop

In my Asp.net MVC program, I have an action method in a controller like this. There are two pieces of codes which perform the same functionality. The question is, why the comment codes not work?(I checked the view, the comment codes cannot generate anything I desire to see, while the other can.) I guess maybe it has something to do with the for-loop, because variable i disappear from memory after the for-loop end. Any thought is of worth, thanks.

        //
        // GET: /Account/Register
        [AllowAnonymous]
        public ActionResult Register(string code, string state)
        {
           ……

            var departments = new List<IEnumerable<SelectListItem>>();

            //functionally equal, but not work.
//            for (int i=0; i< db.Settings.Find(1).MaxDepartmentLevel;i++)
//            {
//                departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level == i+1)));
//
//            }

            //these work.
            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level ==  1)));
            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level ==2)));
            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level == 3)));


            var registerViewModel = new RegisterViewModel()
            {
                OpenId = wechatUserAccessToken.openid,
                Departments = departments,
                    AvatarImageUrl = avatarImageUrl.TrimEnd('0') + "96"
            };

            return View(registerViewModel);
        }

Edit: db.Settings.Find(1).MaxDepartmentLevel=3.

Upvotes: 0

Views: 126

Answers (1)

guo
guo

Reputation: 10229

It's a for loop variable closure issue, which is pointed out by @Ivan in question's comment.

In fact, the code below will not perform as I wish.

  //functionally equal, but not work.
//            for (int i=0; i< db.Settings.Find(1).MaxDepartmentLevel;i++)
//            {
//                departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level == i+1)));
//
//            }

It will perform as this:

            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level ==  4)));
            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level ==4)));
            departments.Add(ToSelectListItems(db.Departments.Where(r => r.Level == 4)));

Above, r.Level == 4 because i in for-loop will be 3 finally and i+1=4at last.

r => r.Level == i+1 is instantiating a delegate, which capture variable i itself but not variable i's value. This is totally different from JAVA.

Some valuable references:

http://csharpindepth.com/Articles/Chapter5/Closures.aspx

https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/

https://stackoverflow.com/a/227833/5835947

Upvotes: 2

Related Questions