I am fairly new to programming and C#, and I am creating a game using C# 9.0 in which all instances of Entity have certain stats. I want to be able to change their private data fields using properties, though I'm not entirely sure how properties work. I know they are useful in encapsulation as getters and setters.
Context:
I am trying to optimize code and decrease memory usage where possible
The byte field str should be variable (through events, training, etc.), but have a "ceiling" and "floor"
If dog.str = 253, then dog.Str += 5; should result in dog.str being 255
If dog.str = 2, then dog.Str -= 5; should result in dog.str being 0
private byte str;
public short Str
{
get => str;
set
{
if (value > byte.MaxValue) str = byte.MaxValue; //Pos Overflow
else if (value < byte.MinValue) str = byte.MinValue; //Neg Overflow
else str = (byte)value;
}
}
Questions:
Since the property is of datatype Short, does it create a new private backing field that consumes memory? Or is value/Str{set;} just a local variable that later disappears?
Does the property public float StrMod {get => (float)(str*Effects.Power);} create a backing field? Would it be better to just create a method like public float getStrMod() instead?
Is this code optimal for what I'm trying to achieve? Is there some better way to do this, considering the following?
If for some reason the Short overflowed (unlikely in this scenario, but there may be a similar situation), then I would end up with the same problem. However, if extra memory allocation isn't an issue, then I could use an int.
The {get;} will return a Short, which may or may not be an issue.
Question 1:
No it doesn't, its backing field is str.
Question 2:
Profile your code first instead of making random changes in hope to reduce memory usage.
"Premature optimization is the root of all evil", do you really have such issues at this point ?
Personally I'd use int and use same type for property and backing field for simplicity.
This would avoid wrapping such as assigning 32768 which would then result as -32768 for short.
Side note, don't think that using byte necessarily results in 1 byte, if you have tight packing requirements then you need to look at StructLayoutAttribute.Pack.
Other than that I see nothing wrong with your code, just get it to work first then optimize it!
Here's how I'd write your code, maybe you'll get some ideas from it:
class Testing
{
private int _value;
public int Value
{
get => _value;
set => _value = Clamp(value, byte.MinValue, byte.MaxValue);
}
private static int Clamp(int value, int min, int max)
{
return Math.Max(min, Math.Min(max, value));
}
}
EDIT:
Different scenarios:
class Testing
{
private int _value1;
public int Value1 // backing field is _value1
{
get => _value1;
set => _value1 = value;
}
public int Value2 { get; set; } // adds a backing field
public int Value3 { get; } // adds a backing field
public int Value4 => 42; // no backing field
}
As you might have guessed, properties are syntactic sugar for methods, they can do 'whatever' under the hood compared to a field which can only be assigned a value to.
Also, one difference with a method is that you can browse its value in the debugger, that's handy.
Suggested reading:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
Finally, properties are expected to return quickly, else write a method, and possibly async if it's going to take a while (advantage to method in this case as properties can't be async).
#aybe answer covers main thing about you question. I would like to add additional info to your 2nd question. You should consider on which platform you write application. There is a word term:
In computing, a word is the natural unit of data used by a particular
processor design. A word is a fixed-sized piece of data handled as a
unit by the instruction set or the hardware of the processor. The
number of bits in a word (the word size, word width, or word length)
is an important characteristic of any specific processor design or
computer architecture.
If processor has 64 bit word, then every variable which type is less than 64 bits will still occupy 64 bits in memory. Keep in mind that variable of given type will be handled as given type and size in memory doesn't impact range, overflow or underflow - arithmetic will be processed for given type.
In short - if you have 64-bit desktop processor and you will use only short variables, then you will not observe any memory savings in comparison to declaring int variables.
Related
I have an array inside a class:
class MatchNode
{
public short X;
public short Y;
public NodeVal[] ControlPoints;
private MatchNode()
{
ControlPoints = new NodeVal[4];
}
}
The NodeVal is:
struct NodeVal
{
public readonly short X;
public readonly short Y;
public NodeVal(short x, short y)
{
X = x;
Y = y;
}
}
Now what if we wanted to take performance to next level and avoid having a separate object for the array. Actually it doesn't have to have an array. The only restriction is that the client code should be able to access NodeVal by index like:
matchNode.ControlPoints[i]
OR
matchNode[i]
and of course the solution should be faster or as fast as array access since it's supposed to be an optimization.
EDIT: As Ryan suggested it seems I should explain more about the motivation:
The MatchNode class is used heavily in the project. Millions of them are used in the project and each are accessed hundreds of times so having them as compact and concise as possible can lead to less cache misses and overall performance.
Let's consider a 64bit machine. In the current implementation the class the array takes 8 bytes for the ControlPoints reference and the size of the array object would be at least 16 bytes of object overhead (for method table and sync block) and 16 byte for the actual byte. So we have at least 24 overhead bytes beside 16 bytes of actual data.
These objects are used in bottlenecks of the project so it matters if we could optimize them more.
Of course we could just have a super big array of NodeVal and just save an index in MatchNode that would locate the actual data but again it will change every client codes that uses the MatchNodes, let alone be a dirty non-object oriented solution.
It is okay to have a messy MatchNode that uses every kind of nasty trick like unsafe or static cache code. It is not okay to leak these optimizations out to the client code.
You´re looking for indexers:
class MatchNode
{
public short X;
public short Y;
private NodeVal[] myField;
public NodeVal this[int i] { get { return myField[i]; } set { myField[i] = value; } }
public MatchNode(int size) { this.myField = new NodeVal[size]; }
}
Now you can simply use this:
var m = new MatchNode(10);
m[0] = new NodeVal();
However I doubt this will affect performance (at least in means of speed) in any way and you should consider the actual problems using a profiling tool (dotTrace for instance). Furthermore this approach will also create a private backing-field which will produce the same memory-footprint.
I have the basics down with properties, but I don't see a real use for them. Doesn't it just return the value of an equation? I mean there is no point in using a property if you could just write down a simple equation for it.
For example:
int currentValue;
public int CurrentValue
{
get { return currentValue; }
set { currentValue = value; }
}
Is the same thing as just:
currentValue;
Another example:
int currentValue;
public int CurrentValue
{
get { return currentValue * 5; }
set { currentValue = value; }
}
Is the same thing as:
currentValue = currentValue * 5;
In your first example, Public Fields versus Automatic Properties is a good answer. Basically, you should use always properties instead of fields for non-private things. This lets you do things like modify the code later without breaking things, and make a private set. Properties can also do things like notify code when they're changed or provide default or calculated values easily. And you can use auto-properties to cut down on extraneous code:
public int CurrentValue { get; set; }
Your second example is not a good use of properties, since it breaks the assumptions of how properties work. E.g. if I set the property to 3 and no exception is thrown, I'd expect it to be 3 when I get it, not 15. currentValue = currentValue * 5;, which could make sense working with a field, property, or local variable, makes the value 5 times larger. Maybe you meant something like this:
int currentBackingValue;
public int CurrentValue
{
get { return currentBackingValue * 5; }
}
Without a set, this can work nicely, and without breaking any conventions and assumptions: CurrentValue is calculated based on currentBackingValue.
(as an aside, you should note that the getters and setters of a property are, in fact, methods, just used with a field-like syntax to replace something like Java's getX/setX standard)
Getters and setters properties are handy if you want to add some extra functionality to your code, centralizing your function so you can change it only in one place. You almost never know when you're going to have to change something, but you can prepare.
This, along with the concepts of encapsulation and information hiding, are basic OOP concepts but very important...
V E R Y I M P O R T A N T
Don't underestimate this tremendous power D:
Its so... powerful...
Properties are also used in a number of other .NET technologies, WPF doesn't work without them (with a PropertyChanged event invoke in the setter) and WCF uses them extensively in data contracts.
Especially relating to WPF, the power of properties is that both the "get" and "set" fields are functions and so can do lots of things besides just returning or setting the backing private member. This comes in handy more times than you may think.
Example property (for WPF)
public String UIDisplayedString
{
get { return _member; }
set
{
_member = value;
PropertyChanged(new PropertyChangedEventArgs("UIDisplayedString"));
}
I need to pass values to a method, along with an indication of whether each value is specified or unspecified, since null is a valid value itself, and therefore cannot be interpreted as "unspecified".
I took the generic approach and created a simple container for such values (see below), but is this the right way to go? Are there better ways to approach this problem - e.g. does a class like this already exist in the framework?
public struct Omissible<T>
{
public readonly T Value;
public readonly bool IsSpecified;
public static readonly Omissible<T> Unspecified;
public Omissible(T value)
{
this.Value = value;
this.IsSpecified = true;
}
}
The method signature could look like the following, allowing the caller to indicate that certain values shouldn't be updated (unspecified), others should be set to null/another value (specified).
public void BulkUpdate(int[] itemIds,
Omissible<int?> value1, Omissible<string> value2) // etc.
This is the best one can theoretically do. In order to distinguish a general T from a "T or null" you need one possible state more than a variable of type T can hold.
For example, a 32 bit int can hold 2^32 states. If you want to save a null value in addition you need 2^32 + 1 possible states which does not fit into a 4 byte location.
So you need a bool value in addition. (Theoretically speaking you just need log2(2^32 + 1) - 32 bits for the Omissible<int> case, but an easy way to store this is a bool).
I have a problem using a class of made of structures.
Here's the basic definition:
using System;
struct Real
{
public double real;
public Real(double real)
{
this.real = real;
}
}
class Record
{
public Real r;
public Record(double r)
{
this.r = new Real(r);
}
public void Test(double origval, double newval)
{
if (this.r.real == newval)
Console.WriteLine("r = newval-test passed\n");
else if (this.r.real == origval)
Console.WriteLine("r = origval-test failed\n");
else
Console.WriteLine("r = neither-test failed\n");
}
}
When I create a non-dynamic (static?) Record, setting the Real works.
When I create a dynamic Record, setting the real doesn't work.
When I create a dynamic Record, replacing the real works.
And here's the test program
class Program
{
static void Main(string[] args)
{
double origval = 8.0;
double newval = 5.0;
// THIS WORKS - create fixed type Record, print, change value, print
Record record1 = new Record(origval);
record1.r.real = newval; // change value ***
record1.Test(origval, newval);
// THIS DOESN'T WORK. change value is not making any change!
dynamic dynrecord2 = new Record(origval);
dynrecord2.r.real = newval; // change value
dynrecord2.Test(origval, newval);
// THIS WORKS - create dynamic type Record, print, change value, print
dynamic dynrecord3 = new Record(origval);
dynamic r = dynrecord3.r; // copy out value
r.real = newval; // change copy
dynrecord3.r = r; // copy in modified value
dynrecord3.Test(origval, newval);
}
}
And here's the output:
r = newval-test passed
r = origval-test failed
r = newval-test passed
When I change the struct Real to class Real, all three cases work.
So what's going on?
Thanks,
Max
dynamic is really a fancy word for object as far as the core CLI is concerned, so you are mutating a boxed copy. This is prone to craziness. Mutating a struct in the first place is really, really prone to error. I would simply make the struct immutable - otherwise you are going to get this over and over.
I dug a little deeper into this problem. Here's an answer from Mads Torgersen of Microsoft.
From Mads:
This is a little unfortunate but by design. In
dynrecord2.r.real = newval; // change value
The value of dynrecord2.r gets boxed, which means copied into its own heap object. That copy is the one getting modified, not the original that you subsequently test.
This is a consequence of the very “local” way in which C# dynamic works. Think about a statement like the above – there are two fundamental ways that we could attack that:
1) Realize at compile time that something dynamic is going on, and essentially move the whole statement to be bound at runtime
2) Bind individual operations at runtime when their constituents are dynamic, returning something dynamic that may in turn cause things to be bound at runtime
In C# we went with the latter, which is nicely compositional, and makes it easy to describe dynamic in terms of the type system, but has some drawbacks – such as boxing of resulting value types for instance.
So what you are seeing is a result of this design choice.
I took another look at the MSIL. It essentially takes
dynrecord2.r.real = newval;
and turns it into:
Real temp = dynrecord2.r;
temp.real = newval;
If dynrecord2.r is a class, it just copies the handle so the change affects the internal field. If dynrecord2.r is a struct, a copy is made, and the change doesn't affect the original.
I'll leave it up to the reader to decide if this is a bug or a feature.
Max
Make your struct immutable and you won't have problems.
struct Real
{
private double real;
public double Real{get{return real;}}
public Real(double real)
{
this.real = real;
}
}
Mutable structs can be useful in native interop or some high performance scenarios, but then you better know what you're doing.
Which is a better programming practice and why?
I have a class like this:
class data {
public double time { get; internal set; }
public double count { get; internal set; }
public average_count { ... }
}
Where average_count should be read_only and give a calculation of count / time.
Is it better to write the accessor as:
public average_count { get {
return (time == 0) ? 0 : (count / time);
}}
Or should I do something like:
private _avg_count;
public average_count {
get
{
return _avg_count;
}
internal set
{
return _avg_count;
}
}
Where _avg_count is updated when in the time and count set accessors?
It seems like the first is easier to read but may be slower if average_count is accessed often. Will the compiler optimizations make the difference insignificant?
Doing it on the fly results in more readable code. Precalculating may improve performance, but you should only do this if (a) it's necessary and (b) you've profiled and it makes a difference.
The bottom line is, readability and maintainability should only be sacrificed for performance when it's absolutely necessary.
This is such a seemingly simple question, yet it's almost impossible to answer. The reason is that what's "right" depends on a number of factors.
1. Performance
In his answer Skilldrick recommends that you prefer what is readable over what performs best as a general rule:
[R]eadability and maintainability should
only be sacrificed for performance
when it's absolutely necessary.
I would counter this by saying that it is only true in a typical business application, where performance and functionality are two clearly distinguishable features. In certain high-performance software scenarios, this is not such an easy thing to say as performance and functionality may become inextricably linked -- that is, if how well your program accomplishes its task depends on how solidly it performs (this is the case at my current place of employment, a company that does algorithmic trading).
So it's a judgment call on your part. The best advice is to profile whenever you have an inkling; and if it's appropriate to sacrifice readability for performance in your case, then you should do so.
2. Memory Usage
0xA3 suggests a fairly elegant approach providing a compromise of sorts: only calculate the value as needed, and then cache it.
The downside to this approach, of course, is that it requires more memory to maintain. An int? requires essentially the same amount of memory as an int plus a bool (which, due to alignment issues, could actually mean 64 bits instead of just 40). If you have loads and loads of instances of this data class and memory is a scarce resource on the platform you're targeting, bloating your type with another 32 bits per instance might not be the smartest move.
3. Maintainability
That said, I do agree in general with what others have said that, all else being equal, you're better off erring on the side of readability so that you can understand your code if and when you revisit it in the future. However, none of the various approaches to this problem is particularly complicated, either.
The bottom line is that only you know your exact circumstances and thus you are in the best position to decide what to do here.
It depends how often you will call average_count and how often count and time are modified. For such kind of optimization I would suggest you to use profiler.
In cases where performance is critical and you need to frequently access the property you have another option as well: Calculating the result when it is needed and then cache the result. The pattern would look like this:
class Foo
{
int? _cachedResult = null;
int _someProperty;
public int SomeProperty
{
get { return _someProperty; }
set { _someProperty = value; _cachedResult = null; }
}
int _someOtherProperty;
public int SomeOtherProperty
{
get { return _someOtherProperty; }
set { _someOtherProperty = value; _cachedResult = null; }
}
public int SomeDerivedProperty
{
get
{
if (_cachedResult == null)
_cachedResult = someExpensiveCalculation();
return (int)_cachedResult;
}
}
}
In this simple case, I would definitely implement the calculated version first; then optimize if neccessary. If you store the value, you will also need extra code to recalculate the value if any of the values it depends on, changes, which leads to possibilities for errors.
Don't optimize prematurely.
I'd go with your first option. These are in-memory objects so the computation on what you're doing is going to be extremely fast. Further, if you created a dedicated property for this (e.g., average_count) then you're going to have to add more code to re-calculate this in the setter for both the time and the count.
As a side note (since you're asking about best practice), you should be using Pascal casing in C# which is initial caps and no underscores.
Will the compiler optimizations make the difference insignificant?
Depends on what you consider "significant". Reading a varaible is rather quick. Dividing two number is rather quick. In fact, depending on what in the RAM cache, reading the variables may take longer than doing the divide.
Use the first method. If it's seems to slow, then consider the second.
If you care about thread safety it may be way easier to do the second option rather than the first.
private double _avg_count;
static readonly object avgLock = new object();
public double time { get; internal set; }
public double count { get; internal set; }
public double average_count {
get
{
return _avg_count;
}
}
private void setAverageCount()
{
_avg_count = time == 0 ? 0 : (count / time);
}
public void Increment()
{
lock (avgLock)
{
count += 1;
setAverageCount();
}
}
public void EndTime(double time)
{
lock (avgLock)
{
time = time;
setAverageCount();
}
}