What am I doing wrong with C# object initializers? - c#

When i initialize an object using the new object initializers in C# I cannot use one of the properties within the class to perform a further action and I do not know why.
My example code:
Person person = new Person { Name = "David", Age = "29" };
Within the Person Class, x will equal 0 (default):
public Person()
{
int x = Age; // x remains 0 - edit age should be Age. This was a typo
}
However person.Age does equal 29. I am sure this is normal, but I would like to understand why.

The properties get set for Name and Age after the constructor 'public Person()' has finished running.
Person person = new Person { Name = "David", Age = "29" };
is equivalent to
Person tempPerson = new Person()
tempPerson.Name = "David";
tempPerson.Age = "29";
Person person = tempPerson;
So, in the constructor Age won't have become 29 yet.
(tempPerson is a unique variable name you don't see in your code that won't clash with other Person instances constructed in this way. tempPerson is necessary to avoid multi-threading issues; its use ensures that the new object doesn't become available to any other thread until after the constructor has been executed and after all of the properties have been initialized.)
If you want to be able to manipulate the Age property in the constructor, then I suggest you create a constructor that takes the age as an argument:
public Person(string name, int age)
{
Name = name;
Age = age;
// Now do something with Age
int x = Age;
// ...
}

Note, as an important technical detail, that:
Person person = new Person { Name = "David", Age = "29" };
is equivalent to:
Person <>0 = new Person(); // a local variable which is not visible within C#
<>0.Name = "David";
<>0.Age = "29";
Person person = <>0;
but is not equivalent to:
Person person = new Person();
person.Name = "David";
person.Age = "29";

Your line of code is identical to:
Person person = new Person() { Name = "David", Age = "29" };
which is identical to:
Person person = new Person();
person.Name = "David";
person.Age = "29";
As you can see; when the constructor executes, Age is not yet set.

Technically, this code:
Person person = new Person { Name = "David", Age = 29 };
is identical to this code:
Person tmpPerson = new Person();
tmpPerson.Name = "David";
tmpPerson.Age = 29;
Person person = tmpPerson;
which is slightly different than what others have posted:
Person person = new Person();
person.Name = "David";
person.Age = 29;
This difference is crucial if your application is using multi-threading.

It looks like you're trying to access Age in the object's constructor. The object initializer values won't be set until after the constructor has executed.
Try this:
Person person = new Person { Name = "David", Age = 29 };
int x = person.Age;
EDIT in response to comment
If you need access to Age in the constructor itself then you'll need to create an explicit constructor with the required parameters, and use that instead of the object initializer syntax. For example:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
int x = Age; // will be 29 in this example
}
}
Person person = new Person("David", 29);

Well, as others said, the parameterless constructor got executed first, hence your quandary.
I do have to ask however, if you've set a field instead of an automatic property for your Age variable?
public class Person
{
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
}
You could use _age instead of x if that's enough, or if you really need to use x:
public class Person
{
private int _age;
private int x;
public int Age
{
get { return _age; }
set
{
_age = value;
x = _age;
}
}
}
Whichever is more appropriate.

Related

Assign value when calling method Syntax in C#

I am sorry I don't know if C# has this syntax or not and I don't know the syntax name. My code below, I want to add 2 people has the same name but not age. So I am wondering if C# has a brief syntax that I can change the Age property value when calling AddPerson method. Please tell me if I can do that? If can, how can I do? Thank you.
class Program
{
static void Main(string[] args)
{
//I want to do this
Person p = new Person
{
Name = "Name1",
//And other propeties
};
AddPerson(p{ Age = 20});
AddPerson(p{ Age = 25}); //Just change Age; same Name and others properties
//Not like this(I am doing)
p.Age = 20;
AddPerson(p);
p.Age = 25;
AddPerson(p);
//Or not like this
AddPerson(new Person() { Name = "Name1", Age = 20 });
AddPerson(new Person() { Name = "Name1", Age = 25 });
}
static void AddPerson(Person p)
{
//Add person
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
//And more
}
If Person is a Record-Type, then yes: by using C# 9.0's new with operator. Note that this requires C# 9.0, also note that Record-Types are immutable.
public record Person( String Name, Int32 Age );
public static void Main()
{
Person p = new Person( "Name1", 20 );
List<Person> people = new List<Person>();
people.Add( p with { Age = 25 } );
people.Add( p with { Age = 30 } );
people.Add( p with { Name = "Name2" } );
}
This is what I see in LinqPad when I run it:

Detail of class in output using list in c#

Here is my person class:
public class Person
{
public string Name;
public string LastName;
public int Age;
public Person()
{
}
public Person(string name, string lastName, int age)
{
Name = name;
LastName = lastName;
Age = age;
}
}
Here is my main program. The current output is ListDemo.Person. ListDemo is my solution name and Person is my class name. How can I get the all details of a person in an output?
class Program
{
static void Main(string[] args)
{
List<Person> personList = new List<Person>();
personList.Add(new Person { Name = "Ahmad", LastName = "Ashfaq", Age = 20 });
personList.Add(new Person { Name = "Ali", LastName = "Murtza", Age = 23 });
foreach (Person item in personList)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
This is pretty simple.
public class Person
{
public string Name;
public string LastName;
public int Age;
public Person()
{
}
public Person(string name, string lastName, int age)
{
Name = name;
LastName = lastName;
Age = age;
}
public override string ToString()
{
return string.Format("{0} {1} - {2} Years Old", Name, LastName, Age);
}
}
Which you can use exactly how you were in the original place:
foreach (Person item in personList)
{
Console.WriteLine(item);
}
Which will print out like:
Jane Doe - 23 Years Old
John Doe - 14 Years Old
Jim Doe - 120 Years Old
The .ToString() is inherited from Object and is available to override on every class you create. You can use it to return string data that represents the object. By default this just returns the type name ListDemo.Person as you found out, but if you override it, you can return whatever you want.
Edite your code to be like this
class Program
{
static void Main(string[] args)
{
List<Person> personList = new List<Person>();
personList.Add(new Person { Name = "Ahmad", LastName = "Ashfaq", Age = 20 });
personList.Add(new Person { Name = "Ali", LastName = "Murtza", Age = 23 });
foreach (Person item in personList)
{
Console.WriteLine(item.Name);
Console.WriteLine(item.LastName);
Console.WriteLine(item.Age);
}
Console.ReadKey();
}
}
Console.WriteLine("Name = {0}, Last Name = {1}, Age = {2}", item.Name, item.LastName, item.Age);
That will output the data you are looking for by going through the properties in the items and giving you the output you desire.
Likewise, if you are looking for default behavior of generating a string from your class, you can override the ToString() method for your class to give the output you desire.
public override string ToString()
{
return string.Format("Name = {0}, Last Name = {1}, Age = {2}", Name, LastName, Age);
}
You have to override te ToString method in your Person class. The result of that function is what's printed. Insert the following code into your Person class:
public override string ToString() {
return string.Format("Name: {0}, LastName: {1}, Age: {2}", Name, LastName, Age);
}
Alternatively, if you do not want the string representation of your class to change. You could print the string generated with the above code instead of printing the object itself.
Beside of using ToString() method that is useful to output single value i am surprised that no one mentioned that you can create custom extension method for IEnumerable<T> (interface that is implemented by List<T>) to print all your values :
public static class Helper
{
public static void Print(this IEnumerable<Person> people)
{
foreach(Person p in people)
Console.WriteLine(string.Format("Name : {0}, Last Name : {1}, Age : {2}", p.Name, p.LastName, p.Age));
}
}
And use it in a way like if it was defined in List<T> :
class Program
{
static void Main(string[] args)
{
List<Person> personList = new List<Person>();
personList.Add(new Person { Name = "Ahmad", LastName = "Ashfaq", Age = 20 });
personList.Add(new Person { Name = "Ali", LastName = "Murtza", Age = 23 });
personList.Print();
}
}

operators in c# for Func<in T, bool>

I need to compare two instance, which are in same type.
public class Person
{
public int Age {get;set;}
public string Name { get;set;}
public static bool operator < (Person p1, Person p2)
{
return p1.Age < p2.Age;
}
public static bool operator > (Person p1, Person p2)
{
return p1.Age > p2.Age;
}
}
Now in Main i have the code:
Person o = new Person()
{
Age = 10,
Name = "Matin"
};
Func<Person, bool> test = person => person < o;
Person o2 = new Person()
{
Age = 9,
Name = "hehe"
};
Console.WriteLine(test(o2));
output: true;
and in my opinion, the 1st person is greater than the second. Could you explain me this situation?
Your code:
Func<Person, bool> test = person => person < o;
So you are passing the person and comparing it with the first one (o).
test(o2)
transforms to the
evaluate `o2 < o`
which is true, as o2.Age < o.Age (9 < 10).
You should implement IComparable like this:
public class Person : IComparable<Person>
{
public int Age { get; set; }
public string Name { get; set; }
public int CompareTo(Person other)
{
return this.Age.CompareTo(other.Age);
}
}
And use it like this:
Person o = new Person()
{
Age = 10,
Name = "Matin"
};
Person o2 = new Person()
{
Age = 9,
Name = "hehe"
}
Console.WriteLine(o.CompareTo(o2));
Your test is:
The person passed to the function must be less than o
In this case, "less than" means "has a lower age than".
Then you pass in o2, so let's see:
o2, age 9
o, age 10
So yes, o2 is less than o.
Output is correct.
In the call to test(o2), the object o2 is passed to test as parameter person.
In this way, the expression o2 < o is evaluated, which yields true, since the Age of o2 is 9, and the Age of o is 10.
The output is true because is exactly that your code says.
to do a good comparation you need two variables (at the moment, you are using all the time "o" instance to compare)
Do Func<Person, Person, bool> test = (person1, person2) => person1 < person2;
and then Console.WriteLine(test(o, o2));

Group a List<Object> into List<List<Object>>

How can I Group a List<Person> Persons by Person.Age using LINQ and create a new List<List<Person>> PersonsByAge ?
public class Person
{
public string Name;
public int Age
}
A GroupBy and a few ToList calls should do the job:
List<Person> persons = ...;
List<List<Person>> byAge = persons
.GroupBy(p => p.Age)
.Select(ps => ps.ToList())
.ToList();
One possible solution would look like this:
var persons = new List<Person>
{
new Person { Age = 20 },
new Person { Age = 30 },
new Person { Age = 20 },
new Person { Age = 40 },
new Person { Age = 50 },
new Person { Age = 50 },
new Person { Age = 20 }
};
var result = from person in persons
group person by person.Age into g
select g.ToList();
var listOfListOfPersons = result.ToList();
This would create a List holding List<Person> items.
Yet another possibility would be to create a class representing the (strongly typed) List<List<Person>> structure:
public class Persons
{
public List<Person> Entries { get; set; }
}
public class Person
{
public Int32 Age { get; set; }
}
and fill it like this:
var result = from person in persons
group person by person.Age into g
select new Persons
{
Entries = g.ToList()
};
var listOfListOfPersons = result.ToList();

c# : how to read from specific index in List<person>

I have a class of persons and list collection as list contains all the values of person class
such as :
List ilist has 2 values [0]={firstname,lastname} . [1]={firstname2,lastname2}
now when i am iterating into the list i am able to print the list but i want to change the value of some parts of my list e.g in index 1 if i want to change the value of firstname2 to firstname3 i am not able to do it . Can anyone tell me how to print the list and then on that index changing any value of the index , i.e. firstname and secondname variable in the person class so that i can update my values
Thanks
According to the docs on msdn you can use the familiar index operator (like on what you use on arrays). So myList[1].lastname = "new last name"; should do it for you.
Docs are here; http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx
Keep in mind you need to do bounds checking before access.
I came here whilst searching for access specific index in object array values C# on Google but instead came to this very confusing question. Now, for those that are looking for a similar solution (get a particular field of an object IList that contains arrays within it as well). Pretty much similar to what the OP explained in his question, you have IList person and person contains firstname, lastname, cell etc and you want to get the firstname of person 1. Here is how you can do it.
Assume we have
IList<object> myMainList = new List<object>();
myMainList.Add(new object[] { 1, "Person 1", "Last Name 1" });
myMainList.Add(new object[] { 2, "Person 2", "Last Name 2" });
At first, I though this would do the trick:
foreach (object person in myMainList)
{
string firstname = person[1].ToString() //trying to access index 1 - looks right at first doesn't it??
}
But surprise surprise, C# compiler complains about it
Cannot apply indexing with [] to an expression of type 'object'
Rookie mistake, but I was banging my head against the wall for a bit. Here is the proper code
foreach (object[] person in myMainList) //cast object[] NOT object
{
string firstname = person[1].ToString() //voila!! we have lift off :)
}
This is for any newbie like me that gets stuck using the same mistake. It happens to the best of us.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
List<Person> list = new List<Person>();
Person oPerson = new Person();
oPerson.Name = "Anshu";
oPerson.Age = 23;
oPerson.Address = " ballia";
list.Add(oPerson);
oPerson = new Person();
oPerson.Name = "Juhi";
oPerson.Age = 23;
oPerson.Address = "Delhi";
list.Add(oPerson);
oPerson = new Person();
oPerson.Name = "Sandeep";
oPerson.Age = 24;
oPerson.Address = " Delhi";
list.Add(oPerson);
int index = 1; // use for getting index basis value
for (int i=0; i<list.Count;i++)
{
Person values = list[i];
if (index == i)
{
Console.WriteLine(values.Name);
Console.WriteLine(values.Age);
Console.WriteLine(values.Address);
break;
}
}
Console.ReadKey();
}
}
class Person
{
string _name;
int _age;
string _address;
public String Name
{
get
{
return _name;
}
set
{
this._name = value;
}
}
public int Age
{
get
{
return _age;
}
set
{
this._age = value;
}
}
public String Address
{
get
{
return _address;
}
set
{
this._address = value;
}
}
}
}
More information on your requirement / why you are accessing the list this way might help provide a better recommendation on approach but:
If you want to use your list in this way frequently an Array or ArrayList may be a better option.
That said, if your specific issue is determining the current element you want to change's ID you can use IndexOf(). (note this will loop the array to find the object's position)
If you just know the index of the element, you can reference as both you and #evanmcdonnal describe.
Lists can be modified directly using their indexer.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
var list = new List<Person>
{
new Person
{
FirstName = "Bob",
LastName = "Carlson"
},
new Person
{
FirstName = "Elizabeth",
LastName = "Carlson"
},
};
// Directly
list[1].FirstName = "Liz";
// In a loop
foreach(var person in list)
{
if(person.FirstName == "Liz")
{
person.FirstName = "Lizzy";
}
}
I do not see where you can meet the problem:
public class Persons
{
public Persons(string first, string last)
{
this.firstName = first;
this.lastName = last;
}
public string firstName { set; get; }
public string lastName { set; get; }
}
...
List<Persons> lst = new List<Persons>();
lst.Add(new Persons("firstname", "lastname"));
lst.Add(new Persons("firstname2", "lastname2"));
for (int i = 0; i < lst.Count; i++)
{
Console.Write("{0}: {2}, {1}", i, lst[i].firstName, lst[i].lastName);
if (i == 1)
{
lst[i].firstName = "firstname3";
lst[i].lastName = "lastname3";
Console.Write(" --> {1}, {0}", lst[i].firstName, lst[i].lastName);
}
Console.WriteLine();
}
}
Output:
0: lastname, firstname
1: lastname2, firstname2 --> lastname3, firstname3

Categories