Read only fields in struct - c#

Perhaps this question some of you have no meaning to it, but I am baffled if any of you can answer me.
Assuming that I have this structure and it has a field or several fields for reading only, how can I assign a value to it through the constructor.
struct PointWithReadOnly
{
// Fields of the structure.
public int X;
public readonly int Y;
public readonly string Name;
// Display the current position and name.
public readonly void Display()
{
Console.WriteLine($"X = {X}, Y = {Y}, Name = {Name}");
}
// A custom constructor.
public PointWithReadOnly(int xPos, int yPos, string name)
{
X = xPos;
Y = yPos;
Name = name;
}
}
To use this struct, add the following :
PointWithReadOnly p1 = new PointWithReadOnly(50,60,"Point w/RO");
p1.Display();
The field is read-only, so how does the code work in this way?

Because readonly field can be assigned either when declared, or in it's class constructor

Related

Constant class variable in c# [duplicate]

This question already has answers here:
How to implement a read only property
(8 answers)
What is the difference between const and readonly in C#?
(30 answers)
Closed 1 year ago.
I want to declare a variable in my class, that cannot be changed later like this:
obj myobj=new obj()
myobj.CONSTANT_VAR="Changed value" //ERROR!!
...but whose value can be accessed like:
Console.WriteLine(myobj.CONSTANT_VAR)
I tried the following:
public class obj{
public int a, b;
public const string CONSTANT_VAR;
public obj(int x,int y){
a=x;
b=y;
CONSTANT_VAR=1/(a*((""+a).Length)+3/(b*((""+b).Length)).ToString();
}
public int do(){
return this.a+this.b-(CONSTANT_VAR).Length;
}
}
class DriverClass(){
static void Main(){
obj myObj=new obj(2,3);
myObj.a=34;
myObj.b=35;
myObj.CONSTANT_VAR="changed ur string lol"; //i want it to print error
Console.WriteLine(CONSTANT_VAR); //no error
Console.WriteLine(myObj.add());
}
}
But i instead get the following error message:
constants must have a value assigned
But i dont want to assign it a value beforehand.....
What do i do?
You're looking for read-only fields or properties, not const which is for genuine global constants.
I'd recommend avoiding public fields entirely, and instead using properties - so in this case you'd want a get-only property. Following .NET naming conventions, you'd have something like:
public class Obj
{
public int A { get; set; }
public int B { get; set; }
public string ConstantVar { get; }
public Obj(int x, int y)
{
A = x;
B = y;
ConstantVar = /* complex expression */
}
public int Do() => A + B - ConstantVar.Length;
}
You can use Readonly, it gives you option to set the value once and can not be changed later.
public class obj(){
public int a, b;
public readonly string CONSTANT_VAR;
public obj(int x,int y){
a=x;
b=y;
CONSTANT_VAR=1/(a*((""+a).Length)+3/(b*((""+b).Length)).ToString();
}
public int do(){
return this.a+this.b-(CONSTANT_VAR).Length;
}
}
class DriverClass(){
static void Main(){
obj myObj=new obj(2,3);
myObj.a=34;
myObj.b=35;
myObj.CONSTANT_VAR="changed ur string lol"; //i want it to print error
Console.WriteLine(CONSTANT_VAR); //no error
Console.WriteLine(myObj.add());
}
}

Accessing fields from a list of structs using a foreach loop

For anyone stumbling on to this question. Unfortunately it was down-voted by over eager commentators before I got the chance to amend it with the error message, which is now included. The question still stands and so do the answers.
I have a struct like this
public struct note{
public note (double SampleTime, string Label)
{
sampleTime = (float)SampleTime;
label = Label;
}
float sampleTime;
string label;
}
I've declared a list which will be comprised of new note structs
public List<note> notesList;
And in some other method initialize it and then add data
notesList = new List<note>();
notesList.Add(new note(Convert.ToDouble(seperatefields[0]),seperatefields[1]));
I'd then like to create a foreach loop and read out the contents of my list
foreach(note n in notesList){
Debug.Log (n.sampleTime);
}
However this won't work.
`rhythmGameUtilityReadFile.note.sampleTime' is inaccessible due to its protection level
Thanks
Jim
Default access modifier in C# is private. Your struct has only private fields, so you cannot access them outside of it. Add public properties to get the values:
public struct Note
{
float sampleTime;
string label;
public Note(double SampleTime, string Label)
{
sampleTime = (float)SampleTime;
label = Label;
}
public float SampleTime { get { return sampleTime; } }
public string Label { get { return label; } }
}
Because you don't have any public field in you struct.
It doesn't work because the field isn't accessible.
Make it public, and make it a property while you're at it.
public struct note
{
public note (double sampleTime, string label)
{
SampleTime = (float)sampleTime;
Label = label;
}
public float SampleTime { get; private set; }
public string Label { get; private set; }
}

Inner class (i.e. non-static nested class) in c#

Assume I've defined an interface with multiple properties, e.g.:
interface IFailable<T>
{
T Value { get; }
bool Success { get; }
}
and I want class Foo to expose multiple readonly instances of this, where IFailable properties are calculated from Foo's private non-static data, how would I do that in c#?
In Java its fairly intuitive.
Here's the best I came up in c#, based on https://stackoverflow.com/a/4770231/146567
First create a wrapper:
public class FailableDelegator<T> : IFailable<T>
{
public delegate T valueDelegate();
public delegate bool successDelegate();
private readonly valueDelegate valueHandler;
private readonly successDelegate successHandler;
public T Value { get { return valueHandler(); } }
public bool Success { get { return successHandler(); } }
public FailableDelegator(valueDelegate v, successDelegate s)
{
valueHandler = v;
successHandler = s;
}
}
Then use it to define the properties in Foo's constructor:
public class Foo
{
private double x = 3;
private double y = -9;
public readonly FailableDelegator<double> xPlusY;
public readonly FailableDelegator<double> sqrtY;
public Foo()
{
xPlusY = new FailableDelegator<double>(() => x + y, () => true);
sqrtY = new FailableDelegator<double>(() => Math.Sqrt(y), () => y>=0);
}
}
I had to put the definitions in Foo's constructor because I got error "cannot access non-static field in static context" if I attempted it directly on the field.
I'm not keen on this, because for less trivial examples you end up with a huge amount of code in Foo's constructor.

Compile Error with Class Inheritance

I am getting a compile error in my PC class on the line where I am setting it's inherited STR stat. The compiler error getting is an "Entity.Stat does not contain a constructor that takes 2 arguments. Now I know this not to be the case, because the base Entity class makes the same declarations in its initialization sequence.
If anyone can take a look to see what I'm doing wrong, that would be great. The StatType item is an ENUM that is declared in another file, and is working without issues.
class PC : Entity {
private Class job;
public PC(string name, Race race, Class job, int STR, int DEX, int CON, int WIS, int INT, int CHA){
this.name = name;
this.race = race;
this.job = job;
// This line here is the line giving me difficulties.
this.STR = new Entity.Stat(STR, StatType.Strength);
}
}
public class Entity
{
protected string name;
protected Race race;
protected Stat STR;
protected Stat DEX;
protected Stat CON;
protected Stat WIS;
protected Stat INT;
protected Stat CHA;
public Entity(){ }
public Entity(string name, Race race, int STR, int DEX, int CON, int WIS, int INT, int CHA){
this.name = name;
this.race = race;
this.STR = new Stat(STR, StatType.Strength);
this.DEX = new Stat(DEX, StatType.Dexterity);
this.CON = new Stat(CON, StatType.Constitution);
this.WIS = new Stat(WIS, StatType.Wisdom);
this.INT = new Stat(INT, StatType.Intelligence);
this.CHA = new Stat(CHA, StatType.Charisma);
}
private struct Stat
{
private int id;
private int value;
private int modifier;
public Stat(int value, StatType id)
{
this.id = (int)id;
this.value = value;
this.modifier = ((value - 10) / 2);
}
public int Value
{
get
{
return this.value;
}
set
{
this.value = value;
this.modifier = ((value - 10) / 2);
}
}
public readonly int Modifier
{
get { return this.modifier; }
}
}
}
Your Stat struct is private, meaning it's only visible to the Entity class, not subclasses. Make it protected and it will be visible to the Entity class and any subclasses.
You can't have readonly properties, either, so you're going to get a compiler error on the line public readonly int Modifier as well.
I believe you need to switch Stat to protected:
protected struct Stat
I don't think that the PC class can see the Stat class because it's not visible to it - only to Entity.

Is there a difference between readonly and { get; }

Do these statements mean the same thing?
int x { get; }
readonly int x;
In answer to your question: There is a difference between readonly and {get; }:
In int x { get; } (which won't compile as there's no way to set x - I think you needed public int x { get; private set; } ) your code can keep changing x
In readonly int x;, x is initialised either in a constructor or inline and then can never change.
readonly int x; declares a readonly field on a class. This field can only be assigned in a constructor and it's value can't change for the lifetime of the class.
int x { get; } declares a readonly auto-implemented property and is, in this form, invalid (because you'd have no way whatsoever to set the value). A normal readonly property does not guarantee to return the same value every time it is called. The value can change throughout the lifetime of the class. For example:
public int RandomNumber
{
get { return new Random().Next(100); }
}
This will return a different number everytime you call it. (Yes, this is a terrible abuse of properties).
No, the statements do not mean the same thing. The full version of the property will have a backing variable:
private int _x;
public int X
{
get { return _x; }
}
Another method in the class could modify the backing variable, changing the value of the property:
private void SomeMethod(int someValue)
{
_x = someValue * 5;
}
The readonly keyword only allows a member variable to be assigned in its declaration or in the constructor:
// Both of these compile
private readonly int _x = 1;
public SomeClass()
{
_x = 5;
}
// This will not compile
private void SomeMethod(int someValue)
{
_x = someValue * 5;
}
So a get-only property whose backing variable is marked readonly is a true read-only property.
Other answers are sorta outdatedā€¦
In newer versions of C# you can assign a default value to int x { get; } = 33; which changes things.
Basically, it gets compiled down to get-only property with a readonly private backing field. (See https://softwareengineering.stackexchange.com/q/372462/81745 for more details)
Another difference I see is that you can't use the readonly version when using interfaces as you can only define methods and properties.
readonly keyword is making sure that these variables dont change once initialised // it is equalant to making a variable private and setting getter for it.
Example.
public class PlayerAuthData
{
public readonly string emailId, password, userName;
private string hello;
public PlayerAuthData(string emailId, string password, string userName)
{
this.emailId = emailId;
this.password = password;
this.userName = userName;
}
public string Hello
{
get { return hello; }
set { hello = value; }
}
}
public class AuthManager
{
void Start()
{
PlayerAuthData pad = new PlayerAuthData("a#a.com", "123123", "Mr.A");
pad.Hello = "Hi there";
print(pad.Hello);
print(pad.password);
print(pad.emailId);
print(pad.userName);
}
}
Literally, there's no big difference because you've declared x to be private (the default). You can always re-compile your class to make x different.
However, if it were public, the definition public int x { get; } allows you to later expand the definition to something like this:
int x { get {
return DoSomeOperation();
}
}
You can do that without breaking your clients. The implementation of the getter is private and clients call it without knowing if it is a static value or has an operation inside its get accessor.
Propery can have backing variable that can be set using any method of that class
private int a;
public int A{get;}
public void ChangeAMethod(int value){
a=value;
}
However readonly fields can only be assigend in constructor or in-line.

Categories