Object refrence error in Parent / Child Relationship class structure - c#

I have following code snippet in c#
public class Customer
{
public Customer()
{
PhoneList = new List<PhoneNumber>();
}
public Customer(int id, string name)
{
this.CustomerID = id;
this.CustomerName = name;
}
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public List<PhoneNumber> PhoneList { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class PhoneNumber
{
public int ID { get; set; }
public int Number { get; set; }
public PhoneNumber()
{
}
public PhoneNumber(int id, int number)
{
this.ID = id;
this.Number = number;
}
}
I am using these classes in UI as bellow
protected void Page_Load(object sender, EventArgs e)
{
List<Customer> list = new List<Customer>();
list.Add(new Customer(2, "John"));
list.Add(new Customer(3, "Joe"));
list.Add(new Customer(4, "Don"));
**list[0].PhoneList.Add(new PhoneNumber(1, 1231213));//Object reference not set to an instance of an object.**
list[0].PhoneList.Add(new PhoneNumber(1, 1231213));
GridView1.DataSource = list;
GridView1.DataBind();
}
When I am executing the page getting Object reference not set to an instance of an object. error message.

While you create Customer.PhoneList in Customer's default constructor you don't create it in the id/name constructor. Either add
PhoneList = new List<PhoneNumber>();
to the second constructor, or chain the constructors with this() syntax:
public Customer(int id, string name) : this()
{
this.CustomerID = id;
this.CustomerName = name;
}
which will call the default constructor first.

Each of the constructors in Customer needs to initialise the PhoneList collection. You're calling the constructor override that takes Id and Name and it doesn't initialise the collection. Change that constructor as follows:
public class Customer
{
public Customer()
{
PhoneList = new List<PhoneNumber>();
}
public Customer(int id, string name)
: this()
{
this.CustomerID = id;
this.CustomerName = name;
}
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public List<PhoneNumber> PhoneList { get; set; }
}

You are not initialising PhoneList in the Customer(int id, string name) constructor, it is therefore null when you add new customers.

null is the default value for reference types. Because you don't initialize your PhoneList before it's usage, it remains to be null and you get this exception

Have you considered initializing PhoneList property in your constructor with parameters? ;)

public Customer(int id, string name)
{
PhoneList = new List<PhoneNumber>(); //this constructor is call
this.CustomerID = id;
this.CustomerName = name;
}
You did not add PhoneList in the other constructor which is being called in your code, So its never initialised

Try doing
public Customer(int id, string name) : this()
{
this.CustomerID = id;
this.CustomerName = name;
}

Related

How to auto assign a foreign key?

I am using SQLite Browser and Dapper. How to auto assign a foreign key from one table to another? I am trying to save a course object's column into the Course table. And how to assign the Course table column PersonID to the Person table's column Person ID?
My thought was to pass in a PersonModel object and a CourseModel object and somehow use the execute method to assign the course.PersonID column. But I can't get it to work.
internal class Program
{
private static void Main(string[] args)
{
PersonModel person = new PersonModel("Jeff");
CourseModel course = new CourseModel("History");
DBAccess.SavePerson(person);
DBAccess.AddCourse(person, course);
Console.ReadLine();
}
}
public class PersonModel
{
public int PersonID { get; set; }
public string Name { get; set; }
public PersonModel(string name)
{
Name = name;
}
}
public class CourseModel
{
public int CourseID { get; set; }
public string CourseName { get; set; }
public int PersonID { get; set; }
public CourseModel(string name)
{
CourseName = name;
}
}
public class DBAccess
{
public static string LoadConnectionString(string id = "Default")
{
return ConfigurationManager.ConnectionStrings[id].ConnectionString;
}
public static void SavePerson(PersonModel person)
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
cnn.Execute("insert into Person (Name) values (#Name)", person);
}
}
public static void AddCourse(PersonModel person, CourseModel course)
{
// I want to log the vales of the course and somewhow assign the "person personid" to the "course personid" which is set as the foreign key in SQLite Browser.
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
cnn.Execute("insert into Course (CourseName) values (#CourseName)", course);
}
}
}
Should just be:
cnn.Execute("Insert into Course (CourseName, PersonId) values
(#CourseName,#PersonId)", new { CourseName = course.CourseName, PersonId =
person.PersonId)`
If Course has its person Id already populated, no need to send it through the method, just use it in the query above.

How to automatically create a default constructor which sets default values

Is there any way to auto generate a constructor which looks like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User(int id, string name)
{
Id = 0;
Name = "";
}
}
Currently I am creating a constructor like that with the refactoring tool (CTRL + .):
public User(int id, string name)
{
Id = id;
Name = name;
}
and editing each line afterwards which is pretty cumbersome when you have 20 properties per class. Is there a better way to that?
(Maybe to define a code snippet, so that we can somehow read the class properties with reflection and define them as snippet parameters?)
If you have a class with 20 properties, why do you need a constructor with 20 parameters? Maybe have a sense, but I usually create constructors to initialize properties that are relevant, to simplify the code, not to set all properties.
For your class, you can set the default values when you define the property and all constructors will use this values as the default.
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = string.Empty;
// Here you can even omit the constructor
public User()
{
}
}
Another thing that maybe useful is define a constructor with X parameters and reuse this constructor in other constructors with less parameters:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User()
: this(0, string.Empty)
{
}
public User(int id, string name)
{
Id = id;
Name = name;
}
}
You can replace this(0, string.Empty) for this(default, default) if you want use the default value of each type.
If you need object create with default value for properties. You can code like this:
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = "";
}
Purpose of quick action "generate constructor" make method contructor for assign value to fields or properties. Don't use it in the case of just assigning default values.
do you mean initialize properties? Initializing properties through the code reflection mechanism also requires one-by-one assignments. For private object properties, it is necessary to de-private encapsulation. The operation of initializing properties in c# is generally to initialize object properties or object initializers in the form of constructors. Thank you hope it helps you
class Program
{
static void Main(string[] args)
{
Student student = new Student()
{
age = 25,
name = "java",
sex = "female"
};
}
class Student
{
public int age { get; set; }
public string name { get; set; }
public string sex { get; set; }
public Student()
{
}
public Student(int age, string name,string sex)
{
this.age = age;
this.name = name;
this.sex = sex;
}
}
}

Cannot use constructor for public class within same namespace due to protection level?

I am currently trying to map alot of channel, and have thus for convenient sake, made a class that can contain the channel properties and a dictionary, that maps an ID to a channel. The dictioanary is on one class and the channel definition is in their own classes but, within the same namespace.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ParentId = System.String;
using ChildIds = System.Collections.Generic.List<int>;
using ChannelName = System.String;
using CatalogEntry = System.Tuple<System.String, System.Collections.Generic.List<int>, System.String>;
namespace example
{
public class ChannelHandler
{
public ChannelName channelname { get; set; }
public ParentId parentid { get; set; }
public ChildIds list_of_childs { get; set; }
public int id;
ChannelHandler(ChannelName name, int id)
{
this.channelname = name;
this.id = id;
}
ChannelHandler(ChannelName name, int id, ParentId parentid)
{
this.channelname = name;
this.id = id;
this.parentid = parentid;
}
}
public class Class1
{
private Dictionary<int?, ChannelHandler> dictionary = new Dictionary<int?, ChannelHandler>();
public void inser_into_dictionary(string path)
{
string[] separatingChars = { " " };
string[] splittedPath = path.Split(separatingChars, StringSplitOptions.RemoveEmptyEntries);
int parentId = 0;
ChannelName parentName = string.Empty;
foreach (string channel_id in splittedPath)
{
ChannelName name = channel_id.Split('_').ElementAt(0);
string id = channel_id.Split('_').ElementAt(1);
int int_id = 0;
if (int.TryParse(id, out int_id))
{
int_id = int.Parse(id);
}
Tuple<string, int> pair_of_channel_and_id = new Tuple<string, int>(name, int_id);
if (this.dictionary.ContainsKey(int_id))
{
// Key exist, meaning this is a parent.
// Child entry has to be updated.
parentId = int_id;
parentName = name;
}
else
{
if (parentId == 0)
{
ChannelHandler channel = new ChannelHandler(name, int_id); //ChannelHandler.ChannelHandler is inaccesible due to protection level.
this.dictionary.Add(int_id, channel);
}
}
}
}
}
}
I seem to be unable to create the object channel as the constructor for the class seem to inaccesible due to protection level? but what protection level - everything is public?
It could look like:
public class ChannelHandler
{
public ChannelName ChannelName { get; set; }
public ParentId ParentId { get; set; }
public List<ChildId> ChildIds { get; set; }
public int Id;
public ChannelHandler(ChannelName name, int id)
{
ChannelName = name;
Id = id;
}
public ChannelHandler(ChannelName name, int id, ParentId parentid)
{
ChannelName = name;
Id = id;
ParentId = parentid;
}
By default, the access level of any element of a class is private. You need to make the constructors either public or internal so that can be accessed externally to the class itself. If you look at this article here it explains how access modifiers affect the accessibility levels of your code.
The other change I made was to change the case of your members to meet c# coding conventions. See here
You:
ChannelHandler(ChannelName name, int id)
{
this.channelname = name;
this.id = id;
}
ChannelHandler(ChannelName name, int id, ParentId parentid)
{
this.channelname = name;
this.id = id;
this.parentid = parentid;
}
All members of classes (and structs) are private per default. In C#, everything has the strictest possible accessibility level if you specify nothing. For direct members of classes or structs (including nested types in the class or struct), that is private.
private means accessible only from within the class/struct itself.
Try this:
internal ChannelHandler(ChannelName name, int id)
{
channelname = name;
this.id = id;
}
internal ChannelHandler(ChannelName name, int id, ParentId parentid)
: this(name, id)
{
this.parentid = parentid;
}
Here, internal on the instance constructors (non-static constructors) means the same internal always means: Accessible to everybody in the same project/assembly.
You declared your class name as public but that is not enough. Every function, including constructors, inside the Class definition that is to be accessible by other classes must be declared public as well. Constructors and methods inside a class without an access modifier is defaulted to to either private or internal depending on the circumstances. More information at this link:
Access modifiers
The class ChannelHandler constructors cannot be called from outside the class because they are private. When you don't specify an access level modifier for methods or fieds, by default, C# compiler will assume it is private. Just add keyword public before constructor definitions:
public class ChannelHandler
{
public ChannelName channelname { get; set; }
public ParentId parentid { get; set; }
public ChildIds list_of_childs { get; set; }
public int id;
public ChannelHandler(ChannelName name, int id)
{
this.channelname = name;
this.id = id;
}
public ChannelHandler(ChannelName name, int id, ParentId parentid)
{
this.channelname = name;
this.id = id;
this.parentid = parentid;
}
}

C# initializing list

Where can I initialize List to let other functions know that it exists so Visual Studio doesn't show any errors. For the time being it looks like this:
namespace ConsoleApplication1
{
public class BazaDanych
{
public class Album
{
public int IDNumber { get; set; }
public string AlbumName { get; set; }
public string Artist { get; set; }
public int ReleaseDate { get; set; }
public int TrackAmount { get; set; }
public string Location { get; set; }
public int Rating { get; set; }
public Album(int _id, string _name, string _artist, int _releasedate, int _trackamount, string _location, int _rating)
{
IDNumber = _id;
AlbumName = _name;
Artist = _artist;
ReleaseDate = _releasedate;
TrackAmount = _trackamount;
Location = _location;
Rating = _rating;
}
}
static int currid = 1;
public void addnew()
{
int ID = currid;
if (ID == 1);
List<Album> AlbumsList = new List<Album>();
//useless for this question
}
public void printlist()
{
foreach ( int i in AlbumsList)
{
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
var db = new BazaDanych();
//useless
db.addnew();
db.addnew();
}
}
}
Visual Studio screams that AlbumsList doesn't exist in print function.
You are declaring AlbymsList inside the addnew() method. This means it is only visible within that method. You need to declare it outside any method.
It should be a class member/property:
public class BazaDanych
{
private List<Album> AlbumsList = new List<Album>();
....
}
First off, move the class definition of Album outside of the class BazaDanych, idealy make a separate class file for it but this would work too
namespace ConsoleApplication1
{
public class Album
{
//Album logic
}
public class BazaDanych
{
//Baza logic
}
}
Second, as Amiros states, move the definition out of the addNew method into the class (BazaDanych) and use this reference within AddNew
public class BazaDanych
{
private List<Album> AlbumsList = new List<Album>();
public void AddNew()
{
AlbumsList.Add(new Album(...));
}
}

Model property initialization

I have this model class "UserProfile", it's the original UserProfile class of Membership with a few added properties and methods.
[Table("UserProfile")]
public class UserProfile
{
public UserProfile()
{
this.DictionaryFrom = "eng";
this.DictionaryTo = "hun";
this.trainingType = "normal";
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string DictionaryFrom { get; set; }
public string DictionaryTo { get; set; }
public string trainingType { get; set; }
public virtual ICollection<ForeignExpression> learnedexpressions { get ; set ; }
}
My problem is that upon registering a new user, the three fields in the constructor don't get the values assigned to them (so, there's a NULL in the database for each of them).
The user can set them by choosing values from a list, but I'd like to have a default value for all of them. What am I doing wrong?
Not being a C# aficionado, I'd do something like this... there's probably a "better" way of doing it.
private string myValue = "default value";
public string MyValue {
get { return myValue; }
set {
if (null != value) { myValue = value; }
}
}

Categories