I am partly modifying an application where I will need to set value of the following constant to the value of the environment variable if exists.
What I already have:
private const string BuildPackagePath = #"\\server\build\";
What I would like to do is:
if (Environment.GetEnvironmentVariable("EnvVar") != null)
Set the property value to = Environment.GetEnvironmentVariable("EnvVar")
else
{Keep default/assigned value}
I understand that the left side of an asignment has to be a variable. I will probably have to change the type but was just wondering if anyone could give me an idea so the structure of current code can be kept as is.
consider using a static property without setter
// evaluates Environment Variable on each call
private static string BuildPackagePath
{
get { return Environment.GetEnvironmentVariable("EnvVar") ?? #"\server\build\"; }
}
static readonly field will evaluate Environment Variable only once (but not immediately at startup When do static variables get initialized in C#?)
private static readonly string BuildPackagePath =
Environment.GetEnvironmentVariable("EnvVar") ?? #"\server\build\";
You can´t modify a constants value, that´s why it´s called constant. However you can use readonly to indicate that the member can be modified only within the constructor:
class MyClass
{
private readonly string BuildPackagePath;
public MyClass()
{
var value = Environment.GetEnvironmentVariable("EnvVar");
if(value != null) this.BuildPackagePath = value;
else this.BuildPackagePath = #"\server\build\";
}
}
Or even shorter using the null-conitional operation:
this.BuildPackagePath = value ?? #"\server\build\";
You can use "readonly" modifier instead of const. Then you can set a value of the field in a constructor of a class. For example:
class SampleClass
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SampleClass()
{
// Initialize a readonly instance field
z = 24;
}
}
Related
As the title says, I would like to set the maximum value of the skill, stam and luck integers to the value of the related *Max integers. The *Max int values are set randomly during the start up of the program and the regular values are changed throughout the running of the program. There may be a few instances where the *Max value gets increased or decreased during play.
public static int skillMax = 0;
public static int stamMax = 0;
public static int luckMax = 0;
public static int skill = skillMax;
public static int stam = stamMax;
public static int luck = luckMax;
As my knowledge of C# is still in its infancy, I have not tried much. However I have searched far and wide on the internet however and not been able to find anything except for the MinValue and MaxValue fields and this piece of code with no explanation:
protected int m_cans;
public int Cans
{
get { return m_cans; }
set {
m_cans = Math.Min(value, 10);
}
}
Thanks in advance for any advice you throw my way!
Explanation for the code: Cans is a property. Properties provide controlled access to class or struct fields (variables). They consist of two methods called get to return a value and set to assign the value. A property can also have only a getter or only a setter.
The property Cans stores its value in a so called backing field. Here m_cans. The setter gets the new value through the keyword value.
Math.Min(value, 10) returns the minimum of the two parameters. I.e., for example, if value is 8, then 8 is assigned to m_cans. If value is 12, then 10 is assigned to m_cans.
You can use this property like this
var obj = new MyCalss(); // Replace by your real class or struct name.
obj.Cans = 20; // Calls the setter with `value` = 20.
int x = obj.Cans; // Calls the getter and returns 10;
Properties help to implement the principle of Information hiding.
You can easily adapt this example your variables. Often class level variables (fields) are prepended with _ to differentiate them from local variables, i.e. variables declared in methods. Properties are written in PascalCase.
private static int _skillMax; // Fields are automatically initialized to the default
// value of their type. For `int` this is `0`.
public static int SkillMax
{
get { return _skillMax; }
set {
_skillMax = value;
_skill = _skillMax; // Automatically initializes the initial value of Skill.
// At program start up you only need to set `SkillMax`.
}
}
private static int _skill;
public static int Skill
{
get { return _skill; }
set { _skill = Math.Min(value, _skillMax); }
}
Create methods to update values
private static void UpdateSkill(int newValue)
{
skill = newValue;
skillMax = newValue > skillMax ? newValue : skillMax;
}
I've seen Marc Gravell's answer from May 8 '09 at 13:29
:
public sealed class WriteOnce<T>
{
private T value;
private bool hasValue;
public override string ToString()
{
return hasValue ? Convert.ToString(value) : "";
}
public T Value
{
get
{
if (!hasValue) throw new InvalidOperationException("Value not set");
return value;
}
set
{
if (hasValue) throw new InvalidOperationException("Value already set");
this.value = value;
this.hasValue = true;
}
}
public T ValueOrDefault { get { return value; } }
public static implicit operator T(WriteOnce<T> value) { return value.Value; }
}
Then use, for example:
readonly WriteOnce<string> name = new WriteOnce<string>();
public WriteOnce<string> Name { get { return name; } }
But i could not understand why would one create readonly WriteOnce<T> if its value is private anyway and it's using a property Value that can only be set once.
Also i couldn't get why would one create a property Name that only enables the get but not the set so:
1.You can't set name's value beacuse it's readonly and
2.You can't set it's value through the property cuz it's only get.
You are confusing quite a few things here.
A readonly field means it can only be assigned inside a constructor or via a field initializer. Now WriteOnce is a reference type, so assigning only means that the value stored in name is a reference to the newly created WriteOnce<string> object.
Nothing stops you from doing whenever you want name.Value = "Hello"; because you are not changing the value of name. name = whatever outside a constructor or a field initializer on the other hand is disallowed becuase you are changing the value of the variable to a new reference, but nothing else.
Name is a readonly property, which has as the backing field name.
A read only propery doesn't let you do Name = new WriteOnce<string>(), but Name.Value = "Hello" is perfectly fine.
Anyhow, nowdays, you'd simply use a readonly autoproperty and let the compiler generate all the plumbing code (backing field):
public WriteOnce<string> Name { get }
readonly means that the object can only be created or changed in the constructor. Making it only private and not readonly would allow any method to create new name field instead. So it's true that you could set the Value only once, but if object is not read only you could completely replace it with the new one.
Creatint readonly WriteOnce means that you can set the name value anytime, not just in the constructor, but once you set the value you can't change it and you can't replace it with the new WriteOnce object.
You could re-write the class as a struct to make it a little simpler and easy to read.
struct WriteOnce<T>
{
public T Value { get; }
public WriteOnce(T input)
{
Value = input;
}
public static implicit operator WriteOnce<T>(T input)
{
return new WriteOnce<T>(input);
}
}
Usage:
WriteOnce<string> name = "test";
You can only change the value on instantiation so you will always know what it will be.
I am writing following code,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ReadOnlyObject
{
class Program
{
private readonly int a = 20;
private readonly int b;
public int propa{get;private set;}
public int propb { get; private set; }
public Program(int tmp)
{
b = tmp;
}
static void Main(string[] args)
{
Program obj1 = new Program(30);
Console.WriteLine(obj1.propa); // Console.WriteLine(obj1.a);
Console.WriteLine(obj1.propb); // Console.WriteLine(obj1.b);
Console.Read();
}
}
}
After executing the above i got o/p as follows,
0
0
And when I change the code by replacing two commented statements printing direct member variables I got output as,
20
30
Why is so?
As far I know about properties they are associated with their definition in order the member variables are declared.
You have confusion about auto property, so:
private readonly int a = 20;
private readonly int b;
public int propa{get {return a; }}
public int propb { get {return b;} private set {b = value;} }
now this will print 20, 30
There are two ways to define properties in C#.
The first, the traditional way;
int myProperty;
public int MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
the second, the auto-property;
public int MyProperty {get;set;}
The first contains a backing variable that you reference in the property accessor. The second implicitly creates a backing variable, because the developers of the language understood that there are a lot of cases where you just need a property!
You can put scope on the auto-property, because you might want to prevent people from setting the value, but internally to the object you should be able to update the value of it.
"As far I know about properties they are associated with their
defination in order the member variables are declated."
Just to clarify all of what you were asking, unless I am reading this statement incorrectly, you're thinking that if you declare variable a and b and the property a and property b that they'll be associated. This is an incorrect assumption.
propa and a are not associated in your example. The compiler is making them auto-implemented properties. http://msdn.microsoft.com/en-us/library/bb384054.aspx If you want propa associated with a then you'd do:
public int propa{get { return a;} }
You're not initializing either property. You also can't set the value of b from a setter if it's marked readonly. You can implement your own 'readonly' type by just not letting the value get set more than once. (Although it doesn't stay true to the constraint that it needs to be initialized in the constructor)
Try this:
private readonly int a = 20;
public int A { get { return a; } }
private int b;
private bool bInitialized = false;
public int B
{
get { return b; }
private set
{
if (bInitialized) return;
bInitialized = true;
b = value;
}
}
The way your code is written propb and propa CANNOT be set outside the scope of the class. so remove the keyword private from the set keyword
if you wrote this.propb = b in your constructor, then I think it should work more like you are expecting.
In the following code:
public class MovieRepository : IMovieRepository
{
private readonly IHtmlDownloader _downloader;
public MovieRepository(IHtmlDownloader downloader)
{
_downloader = downloader;
}
public Movie FindMovieById(string id)
{
var idUri = ...build URI...;
var html = _downloader.DownloadHtml(idUri);
return ...parse ID HTML...;
}
public Movie FindMovieByTitle(string title)
{
var titleUri = ...build URI...;
var html = _downloader.DownloadHtml(titleUri);
return ...parse title HTML...;
}
}
I asked for something to review my code, and someone suggested this approach. My question is why is the IHtmlDownloader variable readonly?
If it's private and readonly, the benefit is that you can't inadvertently change it from another part of that class after it is initialized. The readonly modifier ensures the field can only be given a value during its initialization or in its class constructor.
If something functionally should not change after initialization, it's always good practice to use available language constructs to enforce that.
On a related note, C# 9 introduces the init accessor method for properties, which indicates the property value can only be set during object construction, e.g.:
class InitExample
{
private double _seconds;
public double Seconds
{
get { return _seconds; }
init { _seconds = value; }
}
}
This ensures that the value of _downloader will not be changed after the constructor was executed. Fields marked as readonly can only be assigned a value from within the constructor(s) of a class.
A readonly field is useful for modelling data that should not change after it has been initialized. You can assign a value to a readonly field by using a initializer when you declare it or in a constructor, but thereafter you cannot change it.
I need a field that can be assigned to from where ever I want, but it should be possible to assign it only once (so subsequent assignments should be ignored). How can I do this?
That would not be a readonly field then. Your only options for initializing real readonly fields are field initializer and constructor.
You could however implement a kind of readonly functionality using properties. Make your field as properties. Implement a "freeze instance" method that flipped a flag stating that no more updates to the readonly parts are allowed. Have your setters check this flag.
Keep in mind that you're giving up a compile time check for a runtime check. The compiler will tell you if you try to assign a value to a readonly field from anywhere but the declaration/constructor. With the code below you'll get an exception (or you could ignore the update - neither of which are optimal IMO).
EDIT: to avoid repeating the check you can encapsulate the readonly feature in a class.
Revised implementation could look something like this:
class ReadOnlyField<T> {
public T Value {
get { return _Value; }
set {
if (Frozen) throw new InvalidOperationException();
_Value = value;
}
}
private T _Value;
private bool Frozen;
public void Freeze() {
Frozen = true;
}
}
class Foo {
public readonly ReadOnlyField<int> FakeReadOnly = new ReadOnlyField<int>();
// forward to allow freeze of multiple fields
public void Freeze() {
FakeReadOnly.Freeze();
}
}
Then your code can do something like
var f = new Foo();
f.FakeReadOnly.Value = 42;
f.Freeze();
f.FakeReadOnly.Value = 1337;
The last statement will throw an exception.
Try the following:
class MyClass{
private int num1;
public int Num1
{
get { return num1; }
}
public MyClass()
{
num1=10;
}
}
Or maybe you mean a field that everyone can read but only the class itself can write to? In that case, use a private field with a public getter and a private setter.
private TYPE field;
public TYPE Field
{
get { return field; }
private set { field = value; }
}
or use an automatic property:
public TYPE Field { get; private set; }