I have a simple class that represents 3 dimensional coordinates called Coord3 that simply has x, y, and z int values.
I want to declare a static constant variable Coord3.zero where x, y, and z are set to 0.
I have attempted this with:
public static readonly Coord3 zero = new Coord3(0, 0, 0);
However I found that this variable can be changed. For example if I do
Coord3 coord = Coord3.zero;
coord.x = 5;
this actually changes the x value of Coord3.zero to be 5. Maybe I am misunderstanding readonly? I know that in Unity there is Vector3.zero which never changes. I am trying to achieve the same effect.
Maybe I am misunderstanding readonly?
Yeah, readonly means you can't change the reference of your variable. In other words, you can't write Coord3.zero = new(...);
Now, the way these things are usually written is as structs, where fields are by default immutable. That would solve your problem right there. That is also how it's done in Unity. Note that you can also do this with classes, by having only getters on your properties and filling them in once from your constructor, but classes are very heavy weight for these small types.
readonly is not quite the same thing as immutable in the sense you mean. readonly means you cannot assign to a variable. So you couldn't do
public static readonly Cord3 zero = new Cord3(0, 0, 0);
zero = new Cord3(0, 0, 1);
In order to achieve the effect you want, you could need to create a class, struct or record with readonly properties or fields. There's no way to achieve that effect with a type defined in an internal library. If the type allows mutability on a field or property, that field or property is mutable.
Marking zero as readonly indeed prevents you from changing what zero stores. You cannot reassign it.
zero = new Coord3(1, 1, 1); // error
Note that since Coord3 is a class, zero.x = 5; isn't actually changing what zero stores. You are just changing some property of the object that zero is referring to. zero is still storing the same reference to the same old object.
You could prevent this by not providing any public API in Coord3 that would change its fields' values - for example, by making x, y, z all read-only properties:
public int X { get; }
public int Y { get; }
public int Z { get; }
Of course, this wouldn't work if you just want to prevent setting the properties on zero, but allow the modification of Coord3 on other objects.
I would suggest that you make Coord3 a struct:
public struct Coord3 {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
Now zero stores the fields' values directly, rather than a reference to an object. zero.x = 5; would produce an error, because you are modifying what zero directly stores.
Note that Unity's Vector3 for example, is also a struct.
I think you can make an immutable base class and your Coord3 inheriting this class.
public class BaseCoord3
{
// protected means it can only be used by BaseCoord3 and Coord3
protected int x;
// equivalent to public int X { get { return x; } }
public int X => x;
}
public class Coord3 : BaseCoord3
{
public override int X
{
get { return x; }
set { x = value; }
}
public static BaseCoord3 Zero => new BaseCoord3(0,0,0);
}
This should work similar to the way with Readonly versions of collections in c#. I think the struct solutions are the way to go though.
How about you just use a get-property to never change the zero object?
public class Coord3
{
public static Coord3 Zero => new Coord3(0,0,0);
}
Then you won't be able to change the values of Zero, but you will maintain the functionality of Coord3 objects.
Coord3 a = Coord3.Zero;
a.x = 2; // changes a.x, but not Coord3.Zero.x
Related
I don't want to assign properties one by one. Please do not say, I need to assign 1 by 1. I know IClonable interface but unfortunately, suppose that Point class comes from other library , so I can not modify. How can I achieve cloning object which belongs to other libraries?
In below example, as expected when we change p2, p1 is changed as well. My aim is copying p1, and when I change copy object, I do not want main object to change. Int his example, I want p1 to keep as it was before.
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
Point p1 = new Point(5,6);
Point p2= p1;
p2.X = 9;
Console.WriteLine("x={0}, y={1}", p1.X, p1.Y);
}
class Point
{
// Constructor:
public Point(int x, int y)
{
X = x;
Y = y;
}
// Property implementation:
public int X { get; set; }
public int Y { get; set; }
}
}
You can use the MemberwiseClone method inherited from System.Object:
public Point ShallowClone()
{
return (Point)this.MemberwiseClone();
}
ICloneable is an interface, not a class. Whether you implement ICloneable or not makes no difference regarding assign properties one by one or not.
Other options:
If you have not access to the code of Point or cannot derive your implementation from it:
Use the AutoMapper NuGet package (or one of the various other ones).
Create an extension method.
Make the class immutable. Like this you can just copy the reference around just as with strings.
Implement Point as a struct. Structs can be copied by simple assignment.
Implement Point as a class or struct record which automatically provides value behavior (immutability, value equality) and much more. See: Records (C# reference).
I sorted out this problem with using automapper .
You can check my solution:
https://dotnetfiddle.net/En51IP (using new way )
https://dotnetfiddle.net/iapj84 (using old way )
I have some trouble of using FsCheck on C#. C# version is 7.0.
When using Fscheck, arguments behave as if they have same value when they are set to other object.
Please see the code below.
[Property]
public Property CorrectTest(int x, int y)
{
return ( x == y ).ToProperty();
}
[Property]
public Property WrongTest(double x, double y)
{
Values values = new Values();
SetMethod(values, x, y);
// "True" is always shown
return ( Double.Equals(values.x, values.y) ).ToProperty();
}
public struct Values
{
public double x { get; set; }
public double y { get; set; }
}
private void SetMethod(Values values, double x, double y)
{
values.x = x;
values.y = y;
}
if I perform CorrectTest, the test fails because it is not correct that x is always equal to y.
On the other hand, if I perform WrongTest, the test always passes.
It is totally wrong, but the test cannnot detect the problems.
If you know about the related information and the solution, could you please teach me?
Thanks.
Looks like this is because Values is a struct, i.e. a value type, i.e. the values parameter is copied when you pass it to SetMethod. As a result, the original values variable in WrongTest never gets modified.
Try inlining SetMethod, or passing the values by reference (using the ref keyword).
Also consider making Values an immutable struct with a constructor that takes x and y and no setters, this makes everything a lot clearer especially for structs.
So basically I have this one class called Animal.
In this class I have strings a,b,c,x,y,z;
I want to make an object array for this program so I make one called arr.
For a,b,c,x and y I want to have different values for each object array elements.
I.e.: arr[0].a will be different than arr[1].a, which is different than arr[2].a etc.
However, for the property z, I only want to use one value for the whole of the program, I.e: arr[0].z is the only z value that I want to use. Currently I just call arr[0].z and never use any other number in [].
Is this bad practice and should I make a whole new class, just for property z so that I don't waste memory space? Are there any other problems associated with not using any of the other values of z?
Make the z variable static and in the constructor of you class simply initialize with this value.
You can implement your class in this way.
public class Animal
{
public string A { get; } // related to instance
public string B { get; }
public string C { get; }
public string X { get; }
public string Y { get; }
public string Z // gets or sets static variable which will affect all animals.
{
get { return _z; }
set { _z = value; }
}
private static string _z;
}
Is this bad practice ?
Without context we cant say its always bad design or not. But generally, yes its bad design.
Assuming I have a struct:
struct Vector
{
public int X, Y;
// ...
// some other stuff
}
and a class:
class Map
{
public Vector this[int i]
{
get
{
return elements[i];
}
set
{
elements[i] = value;
}
}
private Vector[] elements
// ...
// some other stuff
}
I want to be able to do something like: map[index].X = 0; but I can't, because the return value is not a variable.
How do I do this, if at all possible?
You should avoid mutable structs.
If you want your type to be mutable use a class instead.
class Vector
{
public int X { get; set; } // Use public properties instead of public fields!
public int Y { get; set; }
// ...
// some other stuff
}
If you want to use a struct, make it immutable:
struct Vector
{
private readonly int x; // Immutable types should have readonly fields.
private readonly int y;
public int X { get { return x; }} // No setter.
public int Y { get { return y; }}
// ...
// some other stuff
}
The compiler prevents you from doing this because the indexer returns a copy of an object not a reference (struct is passed by value). The indexer returns a copy, you modify this copy and you simply don't see any result. The compiler helps you avoid this situation.
If you want to handle such situation you should use class instead or change the way you deal with Vector. You shouldn't modify it's value but initialize it's values in constructor, more on this topic: Why are mutable structs “evil”?.
define Vector as class,
or
store value in a temporary variable
var v = map[index];
v.X = 0;
map[index] = v;
or
add function to change
map[index] = map[index].Offset()
or
let the [] operator return a setter class
class Setter { Vector[] Data; int Index; public double X { get { return Data[Index]; } set { Data[Index] = new Vector(value, Data[Index].Y); }}}
public Setter this[int i]
{
get
{
return new Setter() { Data = elements, Index= i };
}
}
Although generic classes work pretty well for many purposes, they do not provide any reasonable way to access structs by reference. This is unfortunate since in many cases a collection of structs would offer better performance (both reduced memory footprint and improved cache locality) and clearer semantics than a collection of class objects. When using arrays of structs, one can use a statement like ArrayOfRectangle[5].Width += 3; with very clear effect: it will update field X of ArrayOfRectangle[5] but it will not affect field X of any other storage location of type Rectangle. The only things one needs to know to be certain of that are that ArrayOfRectangle is a Rectangle[], and Rectangle is a struct with a public int field X. If Rectangle were a class, and the instance held in ArrayOfRectangle[5] had ever been exposed to the outside world, could be difficult or impossible to determine whether the instance referred to by ArrayOfRectangle[5] was also held by some other code which was expecting that field X of its instance wouldn't change. Such problems are avoided when using structures.
Given the way .net's collections are implemented, the best one can do is usually to make a copy of a struct, modify it, and store it back. Doing that is somewhat icky, but for structs that aren't too big, the improved memory footprint and cache locality achieved by using value types may outweigh the extra code to explicitly copy objects from and to the data structures. It will almost certainly be a major win compared with using immutable class types.
Incidentally, what I'd like to see would be for collections to expose methods like:
OperateOnElement<paramType>(int index, ref T element, ref paramType param, ActionByRef<T,paramType> proc) which would call proc with the appropriate element of the collection along with the passed-in parameter. Such routines could in many cases be called without having to create closures; if such a pattern were standardized, compilers could even use it to auto-generate field-update code nicely.
Kicking around some small structures while answering this post, I came across the following unexpectedly:
The following structure, using an int field is perfectly legal:
struct MyStruct
{
public MyStruct ( int size )
{
this.Size = size; // <-- Legal assignment.
}
public int Size;
}
However, the following structure, using an automatic property does not compile:
struct MyStruct
{
public MyStruct ( int size )
{
this.Size = size; // <-- Compile-Time Error!
}
public int Size{get; set;}
}
The error returned is "The 'this' object cannot be used before all of its fields are assigned to". I know that this is standard procedure for a struct: the backing field for any property must be assigned directly (and not via the property's set accessor) from within the struct's constructor.
A solution is to use an explicit backing field:
struct MyStruct
{
public MyStruct(int size)
{
_size = size;
}
private int _size;
public int Size
{
get { return _size; }
set { _size = value; }
}
}
(Note that VB.NET would not have this issue, because in VB.NET all fields are automatically initialized to 0/null/false when first created.)
This would seem to be an unfortunate limitation when using automatic properties with structs in C#. Thinking conceptually, I was wondering if this wouldn't be a reasonable place for there to be an exception that allows the property set accessor to be called within a struct's constructor, at least for an automatic property?
This is a minor issue, almost an edge-case, but I was wondering what others thought about this...
From C# 6 onward: this is no longer a problem
Becore C# 6, you need to call the default constructor for this to work:
public MyStruct(int size) : this()
{
Size = size;
}
A bigger problem here is that you have a mutable struct. This is never a good idea. I would make it:
public int Size { get; private set; }
Not technically immutable, but close enough.
With recent versions of C#, you can improve on this:
public int Size { get; }
This can now only be assigned in the constructor.
You can fix this by first calling the default constructor:
struct MyStruct
{
public MyStruct(int size) : this()
{
this.Size = size; // <-- now works
}
public int Size { get; set; }
}
Another obscure work-around to this problem is one spotted in the temporary Tuple class in the Managed Extensibility Framework (via Krzysztof Koźmic):
public struct TempTuple<TFirst, TSecond>
{
public TempTuple(TFirst first, TSecond second)
{
this = new TempTuple<TFirst, TSecond>(); // Kung fu!
this.First = first;
this.Second = second;
}
public TFirst First { get; private set; }
public TSecond Second { get; private set; }
(Full source code from Codeplex: Tuple.cs)
I also note that the documentation for CS0188 has been updated to add:
If you see this error when trying to
initialize a property in a struct
constructor, the solution is to change
the constructor parameter to specify
the backing field instead of the
property itself. Auto-implemented
properties should be avoided in
structs because they have no backing
field and therefore cannot be
initialized in any way from the
constructor.
So I take that to mean that the official guidance is to use old-style properties in your structs when you run in to this problem, which is probably less obscure (and more readible) than either of the other two alternatives explored so far.