I'm having trouble understanding how to initialize a C# record using named parameters.. This obviously works with more traditional classes with get; set; (or init) properties. Am I missing some special syntax? The reason it matters is that I prefer this kind of initialization to make the code more readable. Thank you
public record Person(string Name, int Age, double Income);
//this does not work
var p = new Person { Name = "Tim", Age = 40, Income = 55 };
What you're doing won't work because under-the-hood, a three-parameter constructor is generated. Record syntax is just syntactic sugar, and it gets lowered into a normal class with some equality contracts.
What you want to do would require a parameterless constructor.
You have two options, use the constructor with named parameters:
var p = new Person( Name: "Tim", Age: 40, Income: 55);
Or flesh out your record a bit to add a parameterless constructor:
public record Person
{
public Person(string name, int age, double income)
{
Name = name;
Age = age;
Income = income;
}
public Person() {}
public string Name { get; init; }
public int Age { get; init; }
public double Income { get; init; }
}
You can do this and keep the parameter list using a : this() on the constructor, but I find this is just confusing.
If you declare the record as I have, you can use:
var p = new Person { Name = "Tim", Age = 40, Income = 55 };
Related
I have this Employee class:
public class Employee
{
public string Name { get; set; }
public string DateOfBirth { get; set; }
public int PhoneNumber { get; set; }
public Employee(string name, string dateOfBirth, int phoneNumber)
{
this.Name = name;
this.DateOfBirth = dateOfBirth;
this.PhoneNumber = phoneNumber;
}
}
In this program:
namespace modelMIP
{
class Program
{
static void Main(string[] args)
{
var angajat = new Employee()
{
Name = "ion",
DateOfBirth = "28",
PhoneNumber = 0770335978
};
Console.WriteLine(angajat);
}
}
}
i have to create a ToString method for showing an object in this format :
Name | DateOfBirth | PhoneNumber
can anyone help me? what is the problem ?
The Employee constructor takes three arguments, but you're not passing any: new Employee().
You could simply change your initializers to passed constructor arguments:
var angajat = new Employee("ion", "28", 0770335978);
If you like having the properties named, you can use parameter names:
var angajat = new Employee(
name: "ion",
dateOfBirth: "28",
phoneNumber: 0770335978);
Or you could give your Employee class a constructor that takes no arguments, and rely on users to initialize properties they want to initialize.
public Employee()
{
}
This latter would be more dangerous in some ways because people could easily forget to initialize the values.
You may also want to consider using C# 9's new record feature.
public record Employee(string Name, string DateOfBirth, int PhoneNumber);
var angajat = new Employee(
Name: "ion",
DateOfBirth: "28",
PhoneNumber: 0770335978);
The ToString() method, in either case, can look like this:
public override string ToString() => $"{Name} | {DateOfBirth} | {PhoneNumber}";
Try this:
var angajat = new Employee("ion", "28", 0770335978);
You are using a constructor that required you to fill in the parameters to construct the Employee object.
Go learn about constructors
The problem is you're trying to use a default constructor that doesn't exist. Normally, C# will create a default constructor for you... unless you provide a constructor of your own. You did provide a constructor of your own: one that requires three arguments.
Therefore, this code is not valid, because there's no matching constructor for the Employee employee type:
var angajat = new Employee()
{
Name = "ion",
DateOfBirth = "28",
PhoneNumber = 0770335978
};
The object initializer syntax is not the same thing as calling your constructor. You want this, instead:
var angajat = new Employee("ion", "28", 0770335978);
Or change the type to also have a default constructor:
public class Employee
{
public string Name { get; set; }
public string DateOfBirth { get; set; }
public int PhoneNumber { get; set; }
// Default constructor
public Employee() {}
public Employee(string name, string dateOfBirth, int phoneNumber)
{
this.Name = name;
this.DateOfBirth = dateOfBirth;
this.PhoneNumber = phoneNumber;
}
}
Either or both will work. Then you can also override ToString():
public class Employee
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public string PhoneNumber { get; set; }
public Employee() {}
public Employee(string name, DateTime dateOfBirth, string phoneNumber)
{
this.Name = name;
this.DateOfBirth = dateOfBirth;
this.PhoneNumber = phoneNumber;
}
public override string ToString()
{
return $"{Name,-20}|{DateOfBirth,12:d} | {PhoneNumber}";
}
}
I have a question about the following code.
First, these codes worked well.
However, there is no declaration only defined about “courses” in class Student.If in the Constructor of Student the argument is constant, will these code be safe?
Thanks for helping!:)
public class Student
{
public string name;
public int age;
public string[] courses;
public Student(string _name, int _age,params string[] _courses)
{
name = _name;
age = _age;
courses = _courses;//is this OK if _courses is constant?
}
}
public class work : MonoBehaviour
{
void Start()
{
/*
string[] courses={"math", "English"};
Student Tom = new Student("Tom",18,courses);
//It's wrong!
*/
Student Tom = new Student("Tom", 18, "math", "English");
string Tom_text = JsonUtility.ToJson(Tom);
Debug.Log(Tom_text);
}
}
The way you have it, anyone can change the Student object at anytime.
If you do not want anyone changing anything about the Student object once it has been created, then make it immutable like this:
public class Student
{
public string Name { get; private set; }
public int Age { get; private set; }
public IEnumerable<string> Courses { get; private set; }
public Student(string name, int age, params string[] courses)
{
this.Name = name;
this.Age = age;
this.Courses = courses;
}
}
Now people cannot change the the properties because the setters are private.
And to follow the .NET naming convention, do not use - underscores in parameter names and use Pascal Notation for property names. I have removed the underscores and used Pascal Notation for property names.
EDIT
#diemaus mentioned a good point in the comments to this answer, in C# 6:
You can actually remove the private set entirely, and just leave it { get; }. This is allowed as long as long as you only set the properties in the constructor.
I am new to C# but i have a background in PHP. Working some basic stuff in C# i came across some odd thing for me. I want to create an array of arrays in C# with string keys that hold another array of string keys. If I had to do this in PHP it whould look like this:
$workers = array("John" => array("salary" => 1000, "bonus" => 200),
"Michal" => array("salary" => 1500, "bonus" => 0)
);
Digging into C# I found some answers like hashtable or dictionary, but it made me more confused.
C# is not like PHP in that it is not loose so you need to declare exactly what the array (hashtable if you want string keys) can hold. Meaning if you wish to have an array of arrays, then the parent array needs to be told that it holds arrays and cannot hold anything else.
This has basicly been answered here:
How to initialize a dictionary containing lists of dictionaries?
Arrays in .NET doesn't have key-value pairs, so you would need to use a different collection for that, like a dictionary.
The closest to your PHP code would be a dictionary of dictionaries, however a dictionary of custom classes work be more in line with how data is handled in C#.
The class:
public class Worker {
public int Salary { get; set; }
public int Bonus { get; set; }
}
The dictionary:
Dictionary<string, Worker> workers = new Dictionary<string, Worker>();
workers.Add("John", new Worker{ Salary = 1000, Bonus = 200 });
workers.Add("Michal", new Worker{ Salary = 1500, Bonus = 0 });
This allows you to locate a worker by name, and then access the properties. Example:
string name = "John";
Worker w = workers[name];
int salary = w.Salary;
int bonus = w.Bonus;
Create a class for your object Worker:
public class Worker
{
public string Name { get; set; }
public double Salary { get; set; }
public int Bonus { get; set; }
public Worker(string name, double salary, int bonus)
{
this.Name = name;
this.Salary = salary;
this.Bonus = bonus;
}
}
Then create a List of workers:
List<Worker> workers = new List<Worker>() {
new Worker("John", 1000, 200),
new Worker("Michal", 1500, 0)
};
What you can do in c# is something like this :
public class Employee
{
public string Name { get; set; }
public double Salary { get; set; }
public int Bonus { get; set; }
public Employee(string name, double salary, int bonus)
{
this.Name = name;
this.Bonus = bonus;
this.Salary = salary;
}
}
And create dictionary :
Dictionary<string, Employee> emps = new Dictionary<string, Employee>();
emps.Add("Michal", new Employee("Michal", 1500, 0));
emps.Add("John", new Employee("John", 1000, 200));
Or sometimes you may wish to use dynamic and anonymous type for our employees rather then strong type (such as Employee) :
var John = new { Salary = 1000, Bonus = 200 };
var Michal = new { Salary = 1500, Bonus = 0 };
var dict = new Dictionary<string, dynamic>()
{
{"John", John},
{"Michal", Michal},
};
Console.WriteLine(dict["John"].Bonus);
output : 200
I am making a console test with C#.
Actually I have never used of C# but VB.Net. I want to create arrays for one-to-many relationship.
My one is 'A Student' has 'Name','Sex',...,'Courses Taken'.
A Student would take many course, each course has a Title and Included Subject. Each subject has Name, Description and Point.
Like this.
Student
- Name - Sex - Courses Taken
Take Courses
- Course Title - Subject Included
Subject
- Subject Name [Math] [MVC]
- Subject description [Advance] [Building Website]
- Subject Point [6.9] [5.6]
I want to store each entity in Arrays but I don't know how to connect subjects/courses to each Students. And how can I get Student who attending Math or MVC. Because every students can have more then more course/ more than one subjects.
You'll want to create classes to describe your different objects.
class Student
{
string Name { get; set; }
Gender Sex { get; set; } // write an enum for this
IEnumerable<Course> CoursesTaken { get; set; }
}
class Course
{
string Title { get; set; }
Subject Subject { get; set; }
}
class Subject
{
string Name { get; set; }
string Description { get; set; }
double Points { get; set; }
}
Using List to create enumerations of instances of these new types allow you to use LINQ to select or evaluate members of the list (nested for loops work as well):
// populate a list of students called studentList
//...
// use LINQ to select the students you want
var mathResults = studentList.Where(student => student.CoursesTaken.Any(course => course.Subject.Name == "Math"));
I feel like I've done with it in good way...
Pls check my code for my ques! ^^
I first made 3 classes as below..
class Students
{
public string StudentName;
public int StudSize;
public bool StudSex;
public List<Take_Courses> tcourses;
public Students() { }
public Students(string name, int size, bool sex, List<Take_Courses> tcourses)
{
StudentName = name;
StudSize = size;
StudSex = sex;
this.tcourses = tcourses;
}
}
and
class Take_Courses
{
public string classname;
public List<Arr_Courses> arr_Course;
public Take_Courses() { }
public Take_Courses(string classname, List<Arr_Courses> arr_courses)
{
this.classname = classname;
arr_Course = arr_courses;
}
}
class Arr_Courses
{
public string cosname;
public string cosdesc;
public float cospoint;
public Arr_Courses() { }
public Arr_Courses(string name, string description, float point)
{
cosname = name;
cosdesc = description;
cospoint = point;
}
}
I then initialized values in Main class as below;
Arr_Courses acos=new Arr_Courses();
Arr_Courses acos1=new Arr_Courses("Math","Advance Math1",9.5f);
Take_Courses cos=new Take_Courses();
Take_Courses cos_take1=new Take_Courses("Info Tech",new List<Arr_Courses>{acos1});
Students stu=new Students();
Students Stu1 = new Students("Milla", 22, true,new List<Take_Courses>{cos_take1});
I then make another List to be generated names of student and use for looping and assign each one to List.
I think some important part is this.
if (arr_stud[i].tcourses[j].arr_Course[k].cosname.Equals("Math"))
{
Math_Stud++;
MathStudents[i] = arr_stud[i];
}
I am sharing this if anyone needs something like this. Any ungraded codes is appreciated to be shared. Thanks so so.
For example, I have this class
class Person{
private int _id = int.MinValue;
private string _name = string.Empty;
private int _age = int.MinValue;
private string _city = string.Empty;
public string Id{ get { return _id ; } set { _id = value; } }
public string Name{ get { return _name; } set { _name = value; } }
public int Age{ get { return _age; } set { _age = value; } }
public string City{ get { return _city ; } set { _name = city; } }
}
and a list of Person that I show in a table. In this table there is an "edit in place/inline": some Person's property has a cell(td) in the table, so when I edit a cell, via javascript/jquery, I create the json object with the changed value and I send it to server. The json object contains only the property changed: if i edit "Name" the json object will be:
{"obj":{"Id":"1","Name":"Anna"}}
But the object Person to the server comes as
Id = 1, Name = "Anna", Age = 0, City = null
So the problem is: to execute an update stored procedure I must create the object with all original values to exceptions of the modified property. In this example, i want get this object:
Id = 1, Name = "Anna", Age = 25, City = "New York"
To create this object I use this method
public static TEntity CopyTo<TEntity>(this TEntity OriginalEntity, TEntity NewEntity){
PropertyInfo[] oProperties = OriginalEntity.GetType().GetProperties();
foreach (PropertyInfo CurrentProperty in oProperties.Where(p => p.CanWrite))
{
if (CurrentProperty.GetValue(OriginalEntity, null) == null)
{
CurrentProperty.SetValue(OriginalEntity, CurrentProperty.GetValue(NewEntity, null), null);
}
}
return OriginalEntity;
}
If new object Person has a property with null value then I take the orginal value from the original Person (NewEntity). This way doesn't work with number because from client to server the Age property become 0 and not null.
How I can to resolve this problem? To consider that I can not use:
nullable type because I should to modify so many lines of code in the whole project;
the table may not contain all the properties of Person, so I can't create the entire object in javascript and then to change only the value modified.
I hope I was clear enough with my bad english
k; if I re-phrase: you want to copy all properties that have non-null values onto an existing object. Well, the first issue (as you note) is that you can't have an int that is null. Fortunately, you can fix that by simply taking the pragmatic step of making Age and Id a Nullable<int>, aka int?:
class Person
{
public int? Id { get; set; }
public string Name { get; set; }
public int? Age { get; set; }
public string City { get; set; }
}
So now we just have the "copy all non-null values". For that, look at this existing answer, which is a bit like your reflection approach, but it uses IL to be stupidly fast.
Example usage:
var orig = new Person {Id = 1, Name = "Anna"};
var delta = new Person {Id = 1, Age = 25, City = "New York"};
var merged = Merger.Merge(orig, delta);
Console.WriteLine(merged.Id);
Console.WriteLine(merged.Age);
Console.WriteLine(merged.Name);
Console.WriteLine(merged.City);
It could also be tweaked to do an in-place merge over one of the existing objects.