Constructor of a struct copying a struct - c#

I have a struct which is for an Arc.
I created a constructor that accepts an Arc struct type and i want to basically copy the contents to the new struct i am creating but it seems to zero everything out - not sure if i am misunderstanding how this works.
This is what i have:
//constructor, take an arc - copy it but with a new radius
public Arc(Arc a, float radius)
{
this = a;
a.Radius = radius;
}
With the usage
Arc arc1 = new Arc(arc0, arc0.Radius + _width/2f);
arc1.Draw(Color.green,2);
Arc arc2 = new Arc(arc0, arc0.Radius - _width/2f);
arc2.Draw(Color.green,2);
For some reason arc1 and arc2 have default values for all its fields including the radius field.
I was expecting arc1 and arc2 to basically be copies of arc0 but with a new radius.
Is the use of this not applicable for non reference types or something? I can't see why else i am having this problem.

public Arc(Arc a, float radius)
{
this = a;
a.Radius = radius; // <-- This line is the problem
}
Your use of a.Radius = radius means you're overwriting the .Radius member of parameter a, not field this.a.
Value-types, including struct values in .NET, do not share identity - whereas reference-types (class instances, Object, etc) can do (and do by default). So, with limited exceptions, you can think of each struct-variable as holding its own distinct copy of the entire structure instance.
Change your code to this:
public Arc(Arc source, float radius)
{
this = source; // Copy `source` into `this`
this.Radius = radius; // Then overwrite `this.Radius`
}

Related

C# cast float array to struct of floats

I have a float array in C# that stores data. However, I need to cast the data to structures like Vector2, Vector3 etc. The structures are holding only floats, so there is no data type conversion in the matter of bytes, only in access.
Eg.:
struct Vector3
{
public float x;
public float y;
public float z;
//plus some methods
}
I can copy the whole float array to the struct one manually by creating a new array, but that is kind of slow for big ones. I have tried to do conversion in unsafe code, but using generic is not working and creating special method for every struct I have is kind of "weird".
In C++ I have something like this:
float * arrayFloat = ....
Vector3 * arrayVector3 = reinterpret_cast<Vector3 *>(arrayFloat);
but that is not an option in C#...
Any ideas how to achieve this, or how to change the design?
you could add a constructor to your struct:
struct Vector3
{
public float x;
public float y;
public float z;
public Vector3(float[] vals)
{
if(vals.Length != 3)
throw new ArgumentException();
x = vals[0]; y = vals[1]; z = vals[2];
}
}
...elsewhere
float[] myFloats = { 0.0f, 1.1f, 2.2f };
var myVec = new Vector3(myFloats);
if you're asking if there is something that lets you do this without any work, the answer is no. Any conversion from an array to a struct of your choosing has to be implemented by you, preferably in your struct.
I believe this can work for your struct, using .NET Core 2.1's MemoryMarshal methods.
My answer here describes how. The essence is:
var vectors = MemoryMarshal.Cast<float, Vector3>(floatArray.AsSpan());
var firstVector = vectors[0];
This is C#'s equivalent of a reinterpret cast.
I'm new to C#, and i was struggling with the same problem, what i found useful is to use an enumerator which lazily converts every element on access:
IEnumerator<Vector3> Positions()
{
for (int i = 0; i < _positions.Length / 3; ++i)
{
yield return new Vector3(_positions[3*i],
_positions[3*i+1],
_positions[3*i+2]);
}
}
With this you don't need to copy the whole array and compiler most likely will not create new object of type Vector3 in memory instead it will use registers.

C# Structured List

I am having problems with this bit of code
I have this structure
public struct bounds
{
public int xmax = 0;
public int xmin = 0;
public int ymax = 0;
public int ymin = 0;
};
and I make a list out of it
List<bounds> map = new List<bounds>();
I am trying to store the boundaries of a space (or object) in a 2D array (its xmax, xmin, ymin, & ymax) I have this integer y variable which is going to be some number when it gets to this code, but I keep getting red lines under the code associated with my list "map" (i and j are counters for going through the 2D array)
if(!(map.Contains(y))) //if the list doesn't already have this number
{
map.Add(y);
map[y].xmax = i; //and set its xmax, xmin, ymax, ymin
map[y].xmin = i;
map[y].ymax = j;
map[y].ymin = j;
}
if(map[y].xmax < j) // if its already in the list look at the current
map[y].xmax = j; // boundaries and decide if new ones should be set
if(map[y].xmin > j)
map[y].xmin = j;
if (map[y].ymax < j)
map[y].ymax = i;
if(map[y].ymin > j)
map[y].ymin = i;
The reason for this is a struct is a value type.
When you're reading out the struct from the list, you're getting a copy.
As such, this line of code (and all that looks like it):
map[y].xmax = i;
is modifying the copy you got out from the list.
You can counter this by manually retrieving the copy, modifying it, and placing it back into the list.
Note: Mutable structs generates all sorts of problems. The problem you're having is just one of them, but you should not make them mutable.
Also note: You're using the struct value itself as an indexer into the list, I assume this is an error, and that you're actually using an index variable, otherwise you're really having problems.
Here's a general tip though. If Visual Studio is drawing red squigglies under your code, you can hover the mouse over it to get a tooltip telling you what is wrong. It may cryptic to you, but the error message can be googled much easier:
To use the List indexer, you need to pass an int. You're passing a bounds struct here
map[y].xmax = i;
y has to be an int representing the index you want to access. I'm guessing y is a bounds struct because you've used
map.Add(y);
and your map is of type List<bounds>.
If the purpose of a data type is to encapsulate a fixed set of related but independent values (such as the coordinates of a point), an exposed-field structure meets that description better than any other data type. Such structures should not have many instance methods other than overrides of ToString(), Equals(), and GetHashCode(); it's generally better for structures to use static utility methods than instance methods. For example, this would be problematical:
public void UpdateRange(Point pt)
{
if (pt.X > xmax) xmax = pt.X;
if (pt.Y > ymax) ymax = pt.Y;
if (pt.X < xmin) xmin = pt.X;
if (pt.Y < ymin) ymin = pt.Y;
}
but this would not:
public void UpdateRange(ref bounds it, Point pt)
{
if (pt.X > it.xmax) it.xmax = pt.X;
if (pt.Y > it.ymax) it.ymax = pt.Y;
if (pt.X < it.xmin) it.xmin = pt.X;
if (pt.Y < it.ymin) it.ymin = pt.Y;
}
Note that when classes expose properties of a structure type, it is not possible to modify such properties directly. One cannot use something like:
bounds.UpdateRange(ref myList[4], newPoint);
nor, if UpdateRange were an instance method, could one use:
myList[4].UpdateRange(newPoint);
In the latter situation, the code would compile, but wouldn't work. Instead, one has to use something like:
var temp = myList[4];
bounds.UpdateRange(ref temp, newPoint);
mylist[4] = temp;
Note that the instance method and the static method with a ref parameter are semantically identical in the cases where both will compile. The difference between them is that the static method with a ref parameter will only compile in cases where the ref parameter is a modifiable variable, but calling the instance method on a property will cause the compiler to copy that property to a temporary variable, call the instance method on that, and discard the result.
I would suggest that your type is almost a perfect example of something that should be a structure. If it were a mutable class type, it would be unclear when code which passed a reference to an instance was really passing the instantaneous values the instance happened to hold at the time of a call, or was passing a reference to a "live" entity. Using an immutable class type or a so-called immutable struct type [note that there isn't really any such thing as an immutable value type] would make methods like UpdateRange slower to write and to run, while offering no particular benefit.
The one essential thing to note about the structure type is that each field (e.g. xmin) has no meaning other than "the last value that something stored in "xmin", or zero if nothing has been stored there yet. If code writes 256 to xmin and -234 to xmax, then xmin will hold 256 and xmax -234. Any code which takes abounds` and does anything with it should be prepared for such values just as it would be if it took those fields as four separate parameters.

Structs: field must be fully assigned compiler error

I've declared the following struct:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
However I get a compiler error saying the ghosts field must be fully assigned. What I want to do is pass in a Vector2, and a Vector2 array when I create a StartPositions object - making a copy of that array.
How can I do this correctly?
You did not initialize the ghosts array. You need to add a call to new.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
....
}
And you can simplify the code by replacing the for loop with a call to Array.Copy().
Array.Copy(ghostsPosIn, ghosts, ghosts.Length);
You have to initialize your ghosts array first:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
You didn't initialize ghosts array.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
...
ghosts = new Vector2[ghostsPosIn.Length];
...
}
From C# Language Specification;
Actual array instances are created dynamically at run-time using the
new operator. The new operation specifies the length of the new array
instance, which is then fixed for the lifetime of the instance.
One annoying quirk in .net is that unless one is using "unsafe" code the concept of a value-type array does not exist. The struct as shown contains a position for the "pacman" and a reference to a mutable array that holds the positions of the ghosts. This is an evil combination, since the struct may appear to encapsulate the positions of the ghosts, but it does not. Thus, if one were to say:
StartPositions p1 = whatever();
... do some stuff
StartPositions p2 = p1;
p2.pacman.X += 3;
p2.ghosts[0].X += 3;
the code would add three to p2.pacman and p2.ghosts[0]; it would not affect p1.pacman.X but would add three to p1.ghosts[0]. Such behavior would likely cause confusion.
If your intention is that StartPositions will be read-only, it should probably never expose the ghosts array directly; instead, ghosts should be a property of type IList<Vector2>, and your constructor should set it to something like a new ReadOnlyList<Vector2> initialized with a copy of the passed-in positions. If it does that, then ghosts can simply be a read-only property that returns such positions.

How to clone a RectangleF

How do you easily clone (copy) a RectangleF in C#?
There are obviously inelegant ways to do it, such as new RectangleF(r.Location, r.size), but surely there's a .Copy or .Clone method hiding somewhere? But neither of those compiles for me, nor does there appear to be a copy constructor. I suspect there's some simple, C#-standard way of copying any struct, that I just haven't found yet.
In case it matters, my real objective is to make a method that returns an offset version of a rectangle (because, amazingly, RectangleF doesn't have such built in - it has only a mutator method). My best stab at this is:
public static RectangleF Offset(RectangleF r, PointF offset) {
PointF oldLoc = r.Location;
return new RectangleF(new PointF(oldLoc.X+offset.X, oldLoc.Y+offset.Y), r.Size);
}
(Made uglier than it should by be the astounding lack of an addition operator for PointF, but that's another issue.) Is there a simpler way to do this?
RectangleF is a struct i.e. a value type. Consider the following:
public class Program
{
struct S
{
public int i;
}
static void Main(string[] args)
{
S s1 = new S();
S s2 = s1;
s1.i = 5;
Console.WriteLine(s1.i);
Console.WriteLine(s2.i);
}
}
The output is:
5
0
Because S is a struct i.e. s2 is a copy of s1.
A Rect is a struct, a value type.
To clone it just assign it to a new variable.

Trying to reduce GC collections

Can someone please tell me whether AddB below will result in less CLR allocations than AddA? I've examined disassembly and it looks to be the case but I'd like confirmation from the Experts please. Can someone Exchange this information with me please?
Cheers,
Charlie.
namespace A
{
struct Vec2
{
public float x;
public float y;
public Vec2 AddA(Vec2 other)
{
Vec2 v = new Vec2(); // Reference variable
v.x = x + other.x;
v.y = y + other.y;
return v;
}
public Vec2 AddB(Vec2 other)
{
Vec2 v; // Value variable
v.x = x + other.x;
v.y = y + other.y;
return v;
}
}
}
If Vec2 is a struct in both examples, by using Vec2 v = new Vec2(); you are not creating a reference to your struct, you are simply creating a new struct on your stack. If you don't use the new keyword, your struct is nevertheless created on the stack and you can initialize each field separately.
In that case, using the new keyword for a struct does't make much sense if your constructor doesn't accept some meaningful parameters to initialize the data in a single line.
If the first method uses a class instead of a struct, then it does create an object for GC to collect, unlike the second method. Since v in AddB is allocated on the stack, it is not collected, the stack is simply popped when your method is finished.
There's no guarantee for anything. Value items are not necessarily stored in the heap.
See The Stack Is An Implementation Detail by Eric Lippert, and the following second part.
The code in your AddA method simply does the same as:
public Vec2 AddA(Vec2 other) {
Vec2 v;
v.x = 0;
v.y = 0;
v.x = x + other.x;
v.y = y + other.y;
return v;
}
The parameterless constructor of a struct returns the default value for the struct, which is a value where all the members are zeroed out. The value is just returned by the call to the constructor, it's never allocated on the heap.
Also, a mutable struct is generally a bad idea. I would implement it like:
struct Vec2 {
public float X { get; private set; }
public float Y { get; private set; }
public Vec2(float x, float y) {
X = x;
Y = y;
}
public Vec2 Add(Vec2 other) {
return new Vec2(X + other.X, Y + other.Y);
}
}
Note that AddA and AddB do not differ in their memory behaviour, both will be allocated on the stack. What does make a difference is that AddB does not call the default constructor for the type and thereby leaves the fields of the Vec2 uninitialized, whereas AddA will zero them out first.
Having said that I'd imagine that the performance hit of zeroing the contents is probably not measurable (if the JIT compiler doesn't even remove it altogether anyway).
To add to the other answers:
Firstly, the code can be improved by using an appropriate constructor and thus omitting the tedious assignments. This isn't really optional: it should be done. Additionally, it would be good to implement such a structure as an immutable type, i.e. making the fields readonly so chances to it aren't at all possible: thus, you would implement pure value semantics.
Secondly, concerning the question of stack vs. heap allocation: I wouldn't bother too much here anyway: the kind of GC used in .NET is specialized to handle lots of such small allocations: your code would be the optimal scenario as far as the .NET GC is concerned. Don't try to avoid it.

Categories

Resources