How to change an attribute of a public variable fr

2019-06-11 12:29发布

问题:

Sorry about the title, I don't think I could explain it right:

This is a simplified example class, this is working ok. (I also have a Save() method)

   public class busItem
    {

        public Item vItem;

        public busItem(int pItem_Id)
        {
            DBDataContext db = new DBDataContext();

            Item vItemQuery = (from i in db.Items
                               where i.Id == pItem_Id
                               select i).FirstOrDefault();

            vItem = new Item();

            vItem.Id = vItemQuery.Id;
            vItem.Desc = vItemQuery.Desc;

        }
    }

And this is my code-behind call:

busItem item = new busItem(1);
item.vItem.Desc = "new description";

the problem is that when I try passing the "new description", i get a "null reference" exception. How can I do that?

回答1:

First of all, that code doesn't look right for at least 2 reasons. pItem in the query is not declared; did you mean pItem_Id? Also, the line with "new description" doesn't end with a semicolon. Unless I'm looking at the exact code you have, there's a good chance the actual problem win't be visible. Secondly, I suspect the error is not actually when you assign "new description" but when you assign vItem.Desc = vItemQuery.Desc. I don't see how the "new description" line could be a problem, but if the query returned null because it couldn't find the requested object, you'd get an error when trying to get the original/default description.

Edit: Are you sure you didn't exclude some significant piece of code like declaring a local instance of vItem within the constructor?



回答2:

You're probably getting the null reference exception in the constructor. FirstOrDefault() can return null if there are no items in the IEnumerable, in which case accessing Id and Desc will cause an exception. If the constructor completes normally, item.vItem.Desc shouldn't fail.



回答3:

I took the code Vitor posted and added two small mock implementations for DataContext and Item so I have running code. Then I added the code that fails in a test. The test passed no matter what I do with the Item object I add to the collection returned by the DataContext.

The only exception I was able to reproduce occurred in the constructor. The line where the new description is set never failed.

I have added my code below.

On a more general note: Public member variables are generally a sign that the design can be improved. I'd suggest to make this variable private and work from there. In our team we have a rule that member variables cannot be public as they lead to weak designs. Just my two cents.

  public class Item {
     public int Id;
     public string Desc;
  }

  public class DBDataContext {
     public System.Collections.Generic.List<Item> Items {
        get {
           var items = new System.Collections.Generic.List<Item> {
              new Item {
                 Desc = null,
                 Id = 1
              }
           };
           return items;
        }
     }
  }

  public class busItem {

     public Item vItem;

     public busItem(int pItem_Id) {
        DBDataContext db = new DBDataContext();

        Item vItemQuery = (from i in db.Items
                           where i.Id == pItem_Id
                           select i).FirstOrDefault();

        vItem = new Item();

        vItem.Id = vItemQuery.Id;
        vItem.Desc = vItemQuery.Desc;
     }
  }

  [Test]
  public void TestBusItem() {
     busItem item = new busItem(1);
     item.vItem.Desc = "new description";
  }


回答4:

The problem is probably this code:

   Item vItemQuery = (from i in db.Items
                           where i.Id == pItem_Id
                           select i).FirstOrDefault();

FirstOrDefault will return the first item, or the default. As Item is a class, the default value is null, and you can't set a member on a null. You need to to test for null after the above statement, if it is null, instantiate manually. Also, a public field like that is a very bad idea.