c# add object to list via its constructor - c#

Just because of interest ...
Given I have a statically defined List<Car> CarsList, and an object of type Car, can I instantiate a new car and add it to the list, while getting a reference to it, in a one-liner?
If I instantiate a car like c1 = new Car("Honda Civic"), it seems I cannot add the car to the list in its constructor:
public Car (string name) {
_name = name;
CarsList.add(this); // adds null
}
And it seems that I can not do it the other way round either:
c1 = CarsList.add(new Car("Honda Civic")); // does not work, list.add does not return a reference to the newly added object.
Is there any way to achieve what I want?

If I really wanted such a construct, I would add an extension method to List<T> which adds the item to the list and returns the item. I would call that extension method With().
That having been said, adding your Car to the CarsList from within the constructor of Car should not add null. You must be doing something fishy there.

Related

C# method returns list by reference instead of by value

I have a class with a static list as shown below:
public class Context
{
private static readonly List<Definition> definitions;
static Context()
{
definitions = LoadXML("path-to-xml-file.xml"));
}
public static List<Definition> GetDefinitions()
{
return definitions;
}
}
My problem is making calls to GetDefinitions() seems to return the list by reference instead of by value, because when I do this elsewhere in my code:
var defs = Context.GetDefinitions().ToList();
defs.ForEach(a =>
{
a.Name = a.Alias ?? a.Name;
});
all subsequent calls to Context.GetDefinitions() will return the modified list - not the original one, hence my conclusion that defs is not a value but a reference to the definitions list.
I tried adding the .ToList() in an attempt to decouple the reference but still I get the same result.
I am also open to a workaround, which allows me to use .Select() instead of .ForEach() in my sample code.
The problem is that the list does not store the items itself, but rather references to the items. Even if you create a new list (e.g. with ToList()), the referenced items stay the same.
In order to fix this, you need to clone the items in the list so that you have a independent copy of the data. You can implement ICloneable on the items and use return the list like this:
public static List<Definition> GetDefinitions()
{
return definitions.Select(x => (Definition)x.Clone()).ToList();
}
This way you create a new list that contains the cloned items. However, cloning an item is a tedious task if you need to clone a deeply nested class structure. For a flat structure, using MemberwiseClone is an easy way.

Method that assigns a value to a variable in all classes in a list

I have a list of classes.
For Example:
public class Object()
{
public string a;
public string b;
}
public List<Object> Objects = new list<Object>();
What I want is a Method that can set the string a in each Object in the List to Object[0].a;
And I want to do this to b and a lot of other vars too with a single Method.
(Other var types to, with only one Method)
is this possible?
Let's say you want a list of ten of those Object (unfortunately named) class instances in a list, and you want them all to have the a property set to "Foo". You can use Enumerable.Range to create an enumeration with ten elements, then Select to create the objects. When creating the object, you can initialize the a property using initializer syntax. Once they are created you can create the list with ToList.
Technically this is one line of code although for readability it may be a good idea to span it across a few visual lines.
List<Object> myList = Enumerable
.Range(0,10)
.Select
(
i => new Object { a = "Foo" }
)
.ToList();

Overriding Base Property and Accessing Reference in Base

In the code below I have a property in base class which returns a list of custom objects. In the parent class I override this property and in the definition of the override I access the reference to the list of custom objects from the base class and add 2 objects to it.
Before returning I put a breakpoint in the code and check the content of the base property and notice that the two new objects are not there. Then I tried storing the reference to the list of objects in the base class locally and added two objects in the list again. I notice that in the local reference the 2 new objects have been added.
However, using both methods I'm pointing to the same reference so I should be able to add objects by referring to the base.TestProperty. Any idea why that won't work?
public override List<CustomObject> TestProperty
{
get
{
List<CustomObject> temp = base.TestProperty;
CustomObject obj1 = new CustomObject()
{
Name = "My Name"
};
CustomObject obj2 = new CustomObject()
{
Name = "Your Name"
};
// Adding to the base list
base.TestProperty.Add(obj1);
base.TestProperty.Add(obj2);
// Adding to temp list, which still points to the base list
temp.Add(obj1);
temp.Add(obj2);
// Base object doesnot contain obj1 and obj2, but the temp object does.
return base.TestProperty;
}
}
This isn't really the specific answer you're looking for, but... you should really reconsider your design.
You've got a property in your subclass... and getting that property changes your class' values. That's extremely counterintuitive. It's not like you'd expect:
Color bgCol = Color.Red;
int red = bgCol.R;
... that second statement to change values of your variable just by accessing one of its properties! How confused would you be if, when running that second statement, it changed the contents of bgCol to yellow?
My advice? Have the base class return what it's supposed to - forgetting about the subclass. And if your subclass needs to add values to that result? Then have it add the values when the subclass's property is called - but only to the result it's passing back - don't have it mess with the base object's properties at all.
public override List<CustomObject> TestProperty
{
get
{
List<CustomObject> objectsFromBase = base.TestProperty;
List<CustomObject> objectsFromThisClass = GetMySubclassCustomObjects();
List<CustomObject> retVal = new List<CustomObject>();
retVal.AddRange(objectsFromBase);
retVal.AddRange(objectsFromSubclass);
return retVal;
}
}
private List<CustomObject> GetMySubclassCustomObjects()
{
// your code for those two CustomObjects, and returning them from a list
}

Taking an object and adding it to the appropritae collection

I am doing a few labs and it has me creating multiple classes that are inheriting from a base class. i have created the base class, a student class that inherits from the base class, which creates a student and a teacher class that inherits from the base class, which creates a teacher. Now i am working on creating a school class that does not inherit any class. i have done most of what it is wanting me to do, but i am stuck on creating the appropriate methods to add the objects to its appropriate classes. I need assistance and guidance on how to create these methods so i may proceed. I am just going to post the Student class that i am working in right now and the instructions. I am not looking for someone to do my homework for me, i just cant seem to find anything online that can guide me in the right directions. thank you for your help.
Methods
Add(base) - Takes a teacher/student object and adds it to the
appropriate collection.
Print(base[]) - Private method that takes an
array of your base class object and prints all the elements of the
array.
3 Print(bool students = true) - Public method that prints out the
list of students, or list of teachers based upon the parameter value.
This is done by calling the Print(base[]) with the student[] or
teacher[] based upon the bool.
namespace BaseClass
{
class School
{
List<Teacher> staff = new List<Teacher>();
List<Student> students = new List<Student>();
public Student Students
{
get
{
students.Count();
return Students;
}
}
public Teacher Staff
{
get
{
if(Staff.EnumProp == Status.Employeed)
{
staff.Count();
}
return Staff;
}
}
public void Add(Teacher t1, Student s1) //not sure if this is correct or
//what to do in this method??
{
staff.Add(t1);
students.Add(s1);
//i also need help in the following methods. i am not sure what needs to be put
//in the parameter of the method, based on the instructions.
Based on requirement 1, you'd have to Add(Base c) and determine the collection to add to from there. e.g. (c is Teacher ? staff : students).Add(c). Normally such a class would have overloads (Add(Teacher) and Add(Student)) separately as well to be able to add directly.
public void Add(Base c)
{
if(c is Teacher)
staff.Add((Teacher)c);
else
students.Add((Student)c);
}
2 depends on the output type. With assignments outputting to the console is often enough, so you can use something like
void Print(params Base[] peeps)
{
foreach(var c in peeps)
c.Print();
}
No matter how Print is implemented, step 3 is actually very easy. You can just call your Print(Base[]) as stated in the requirements. To get that array, you have to determine which collection to use, just as in req. 1. (it does sound like 2 separate collections are wanted, otherwise a single collection could be used where Base exposes the role of the person).
public void Print(bool students = true)
{
if(students)
Print(this.students.ToArray());
else
Print(staff.ToArray());
}
PS, as mentioned in the comments the Students and Staff properties seem to expose some behavior that could be changed, but since that outside the scope of the question, won't go there unless you want us to ;)
Add(base) - Takes a teacher/student object and adds it to the appropriate collection.
For adding you can have two methods with same name but different signature. they are called method overloads. Compiler can distinguish between them by looking at the parameters they take.
These methods are both defined in base method. but better design would be to put each method in its appropriate class. (i.e Teacher and Student class)
public void Add(Teacher teacher)
{
staff.Add(teacher);
}
public void Add(Student student)
{
students.Add(student);
}
Print(base[]) - Private method that takes an array of your base class object and prints all the elements of the array.
If i understood correctly you want to print all elements of student or teacher. thats all?
In your base class you can have private method that prints array.
private void Print(Base[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i].ToString());
}
}
It is better to override ToString method for both Student and Teacher class. for example this method is required in both classes.
public override string ToString() // write this method in both student and teacher classes.
{
return string.Format("Name : {0} , Age : {1}",studentName,studentAge ); // return optional information of student instance.
}
3 Print(bool students = true) - Public method that prints out the list of students, or list of teachers based upon the parameter value. This is done by calling the Print(base[]) with the student[] or teacher[] based upon the bool.
You just need a simple check.
public void Print(bool students = true)
{
if(students)
Print(Students.ToArray());
else
Print(Staff.ToArray());
}
This only works if its inside Base class behind Print(base[]). Otherwise Print(base[]) have to be protected.
A better design would be to add each print method in child classes separately.
In your get and set method what you are doing is really useless.
Count() is a linq method that counts and gives you the length of list. you can use the property of list itself. Count(without parenthesis) which directly gives you the length of list.
Also you dont store the result anywhere so thats why i said its useless. You may want to store the total count. then you can do this.
public int TotalCount
{
get { return staff.Count + students.Count; }
}

Is value in the dictionary becomes a pointer?

If I put an object in the dictionary, whether it becomes a pointer?
I have the following dictionary:
public Dictionary<string, Class1> Dic{ get; set; }
In the following function I update / add to the dictionary
private void Update(string Name)
{
if (Name== null || Name=="")
return;
if (Dic.ContainsKey(Name))
{
Dic[Name] = MyClass;
}
else
{
Dic.Add(Name, MyClass);
}
}
MyClass is a variable that sitting in the same class with the dictionary
public Class1 MyClass { get; set; }
When i changed the class i call to update function, i see that all the dictionary contaion the same value: current MyClass , why?
How can I prevent this?
You are adding the same class object against multiple keys in your dictionary, but all of them are pointing to the same object that is why when you change one object, you see the changes across the dictionary. You need to make copy of your class object and then add it to the dictionary.
You may see this discussion: How do you do a deep copy an object in .Net (C# specifically)? on Stackoverflow.
Other than that, you can get rid of your check against keys, since you are checking if the key doesn't exist add, otherwise update. you can simply do:
private void Update(string Name)
{
if (Name== null || Name=="")
return;
Dic[Name] = MyClass;
}
Which would do the same (add if doesn't exist and update if exist)
Because the class you put in is by reference, so when you change it someplace, it 'changes' there, too (it doesn't really change there, it only changes in one place, but we're all looking at the same thing, so to speak). So, it's nothing really to do with the dictionary, but the mechanics of .NET.
You wouldn't see such changes reflected if you put a value type in, say an integer, then changed the variable value. You could define structures, if appropriate for your situation, which are value types, and you could 'reuse' the type without 'cascading changes'.
No. And sort-of-yes. You never "put and object in the dictionary" - you actually put a reference to an object into the dictionary. The reference points to the original object : the object is not cloned.
If Class1 was a struct, then it would indeed be copied whenever you access it or insert it.
In human terms: a reference is the written address to a house, say. Lots of people can have a copy of that address. If somebody goes to the house and paints the door red, then that is seen by everyone who looks at that address.
(I think I stole this analogy from Jon; sorry Jon)
It sounds like you are doing something like:
MyClass obj = new MyClass();
foreach(var name in names) {
obj.Update(name);
}
when you should be doing:
foreach(var name in names) {
MyClass obj = new MyClass();
obj.Update(name);
}
The distinction here is how many objects we have.
Because class is a reference type. That means every variable of that type is a pointer to that type.
Your class is a reference type, so Dictionary contains it's memory link. Actually you can check more at reference types and value types

Categories