private init in C# props? - c#

What does private access modifier for init only setter in C# mean? I usually make setter as private for most of the properties in my domain classes. With init, does it matter?
The following seem to work without any problem, the compiler does not complain.
public class Point
{
public int X { get; private init; }
public int Y { get; private init; }
}
So how is the above different from the below. There is not private below.
public class Point
{
public int X { get; init; }
public int Y { get; init; }
}

It affects where the setter can be called from, just like normal setters.
Consider this code:
public class Point
{
public int X { get; private init; }
public int Y { get; private init; }
}
class Program
{
static void Main()
{
var point = new Point { X = 10, Y = 20 };
}
}
That fails with two compile-time errors:
The property or indexer 'Point.X' cannot be used in this context because the set accessor is inaccessible
(and the equivalent for Y).
The same initializer would be valid in the Point class, because the set accessors are accessible there. For example, you might want to use a public factory method, which is implemented with an object initializer:
public class Point
{
public int X { get; private init; }
public int Y { get; private init; }
public static Point FromXY(int x, int y) =>
new Point { X = x, Y = y };
}
(There are various reasons why that might not be ideal, or you might prefer to add parameters to a private constructor, but it's an example of where the private init-only setters are accessible.)
Likewise the code above would be valid without the private part of the set accessors, because then they can be called from anywhere (as part of an object initializer).

The init keyword was added in c# 9.0 in order to add immutable properties on objects.
The problem we used to have is that if you have this object you could still modify the Name property (although it has a private setter) via a public method. for example:
public class Person
{
public Person(string name)
{
this.Name = name;
}
public void SetName(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
And we also couldn't use object initializers
var person = new Person
{
Name = "Jane Doe" // Compile Error
};
Now, if we change the code to use init
public class Person
{
public Person(string name)
{
this.Name = name;
}
public string Name { get; init; }
}
We are now able to use object initializers
var person = new Person
{
Name = "Jane Doe" // No error
};
But, if we use your private init like your example
public class Person
{
public Person(string name)
{
this.Name = name;
}
public string Name { get; private init; }
}
We won't be able to use object initializers
var person = new Person
{
Name = "Jane Doe" // Compile error
};

Related

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 add items to a Dictionary from within the class

I am working on a learning project in which I am trying to learn better practices. I have a class, Player, the Player among other things has Dictionary called Items, where items can be stored. The Player is initialized with just a Name and an Age, the Dictionary is supposed to be empty at the initialization of the Player.
Alongside the story, the Player can get items which will be stored in the inventory, so I am trying to create a method that can be called to do this, however I face the following issue:
If the method is not static, it cannot be called from outside the class with the following error:
An object reference is required for the non-static field, method, or property 'Player.AddItems(int, string)'.
If the method is static, it does not see the Items Dictionar with the following error:
An object reference is required for the non-static field, method, or property 'Player.Items'.
I am trying to call it from the main function (will become a class later) with:
Player.AddItems(0, "Wallet");.
Any suggestions are appreciated.
class Player
{
public string Name { get; set; }
public int Age { get; set; }
public Dictionary<int, string> Items { get; set; }
public float Damage { get; set; }
public float Health { get; set; }
public Player(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
this.Items = new Dictionary<int, string>();
this.Damage = 0;
this.Health = 20;
}
public void AddItems(int key, string item)
{
this.Items.Add(key, item);
}
}
An object reference is required for the non-static field, method, or
property 'Player.AddItems(int, string)'
You need to create an object first to call a non-static method of a class.
Player p = new Player("John", "25");
p.AddItems(1, "Data");
An object reference is required for the non-static field, method, or
property 'Player.Items'.
You can't access non-static members from static methods
PS: You can assign default values to properties directly.
class Player
{
public Player(string Name, int Age) : this()
{
this.Name = Name;
this.Age = Age;
}
public string Name { get; set; }
public int Age { get; set; }
public Dictionary<int, string> Items { get; set; } = new Dictionary<int, string>();
public float Health { get; set; } = 20;
public float Damage { get; set; }
public void AddItems(int key, string item)
{
this.Items.Add(key, item);
}
}

C# questions regarding coding

If I have a Pet class with the get set methods for int, double and bool
is this correct?
public class Pet
{
private string name;
private bool age;
public Pet(string name, bool age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
set { name = value; }
}
public bool Age
{
get { return age; }
set { age = value; }
}
}
Main Method
Pet myPet = new Pet ("james", true);
would it be fine to put true in the object for bool?
No.
For this you'll have to create a custom constructor like:
public class Pet
{
public string Name { get; set; }
public float Weight { get; set; }
public bool Alive { get; set; }
//defining a custom constructor
public Pet(string name, float weight, bool alive)
{
this.Name = name; //assign input parameter value to the Property
this.Weight = weight;
this.Alive = alive;
}
}
If your class has int, double and bool properties then this object constructor
Pet myPet = new Pet("fish", 20.0, true);
Would not compile. The "fish" parameter is a string and the compiler will fail (assuming you're setting the property values in the object constructor)
You need an constructor for it:
public class Pet
{
public Pet(string type, double price, bool something)
{
}
}

ReadOnly Property C#

I want have readonly property in a Data Transfer Object,DTO object, without set; accessor like:
public class ViewBannerDTO
{
public int Id { get; }
}
but why get:
'ViewBannerDTO.Id.get' must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors.
and also why i cant:
public readonly int Id{get;}
You can't have no setter for an auto-implemented property (otherwise how would you set it?). You can either add a getter implementation (and a backing field if necessary) or use a private setter:
public class ViewBannerDTO
{
public int Id { get; private set; }
}
Why i cant I do:
public readonly int Id{get;}
because readonly only applies to fields. You can accomplish the same thing with a property by using a readonly backing field and no set accessor:
private readonly int _Id;
public int Id {get { return _Id; } }
but you can't have a readonly auto-implement property because there's no syntax to initialize a property without a set accessor.
It is exactly what is sais: There is not set accessor for that variable and you have no Get method implemented which can do stuff to get you a value.
Either go:
public int Id { get; set; }
OR
public int Id
{
get
{
int something = GetStuffDone();
return something;
}
}
Another something you can do is make the set function private like this:
public int Id { get; private set; }
And an answer to why you cant: The value will never be set cause it has no accessor.
This is just a repeat of answers but OP does not understand
public class ViewBannerDTO
{
public int Id { get; private set; }
public ViewBannerDTO ()
{
Id = 12; // inside the class can assign private
// private not seen outside the classs
}
}
or you could
public class ViewBannerDTO
{
private int id = 12;
public int Id { get { return id; } }
}
or you could
public class ViewBannerDTO
{
public int Id { get { return 12; }
}
As of C# 9 you can get read-only behavior by using an init accessor. Example:
public class Foo
{
public int Bar { get; init;} = 1
public int Baz { get; private init;} = 2
}
var foo = new Foo { Baz = 3};
In both cases the property can only be set during object construction. The private keyword ensures only the class can set the value, otherwise the caller of new can set the value with the object literal notation in the example.
reference: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init

When to use constructor?

Im learning c# online, and I just finished an exercise, were I should create a class called "People" and create 5 variables that can make the peoples uniqe:
public string name;
public int age;
public double heigth;
public double weigth;
public string nationality;
public int shoeSize;
I also created a class called "Bank" and declaired 4 members:
int accountNumber;
string firstName;
string lastName;
string bankName;
then, I got the question: "If you think that the bank class is associated with one person (People class) how would you use the class "People" in the class for "Bank" ?
Now I clearly didnĀ“t understand what was being ment.. Any ideas`?
Edit: when do I need the constructor method?
That's not a constructor, that's trying to teach you that you can have classes you created as properties inside another class you create.
In their example, one person is per bank, so you could have the People class as a property called Person to signify who the account belongs to. You can do this by adding the following to your Bank class:
public People person { get; set; }
In terms of a constructor, you'd need one if you wanted to set some default properties. Consider this constructor for Bank:
public Bank()
{
accountNumber = 1;
firstName = "Default";
lastName = "Default";
bankName = "Default";
person = new People();
}
See that last line that creates person? If you removed that, but then tried to do this.person.name you'd get a NullReferenceException. That's because by default your person would have the value of null.
It could be as simple as:
public class People // I would call it person though, as People is plural
{
public int age;
public double heigth;
public double weigth;
public string nationality;
public int shoeSize;
}
public class Bank // I would call it BankAccount though
{
int accountNumber;
string firstName;
string lastName;
string bankName;
// The answer to the question:
People owner; // <-- Here the bank account has a reference to the People class,
// you provided in the constructor
// And if you need the constructor
public Bank(People owner, int accountNumber)// <-- This is the constructor
{
this.accountNumber = accountNumber;
this.owner = owner;
} // <-- The constructor ends here.
}
How about
public class Person
{
//A property for Name
//A property for Address
}
In another class a property for collection of Persons
public List<Person> People { get; set; }
Thats the way I would go:
public class Person
{
public int Age { get; set; } // I would use properties and public properties are
// starting with a great letter
public double Heigth { get; set; }
public double Weigth { get; set; }
public string Nationality { get; set; }
public int ShoeSize { get; set; }
}
public class BankAccount
{
private Person _person; // private field for the person object
public int AccountNumber { get; private set; } // public propertie for the account
// number with a private setter
// because normally you want to read
// that from the outside but not set
// from the outside
public string FirstName
{
get { return _person.FirstName; }
}
public string LastName;
{
get { return _person.LastName; }
}
public string BankName { get; set; }
public Bank(Person person, int accountNumber)
{
AccountNumber = accountNumber;
_person = person;
}
}
Please allways write down the access parameters from properties, methods etc.

Categories