Indexer that points to item in struct array don't work - c#

I have a class called Surface, in this class i have an array of type struct Color.
public class Surface
{
private Color[,] pixels;
public Color this[int x, int y]
{
get { return pixels[y, x]; }
}
}
[StructLayout(LayoutKind.Explicit)]
public struct Color
{
[FieldOffset(0)]
public byte R;
public void Set(byte r)
{
R = r;
}
}
However when i try to access the color using the indexer it don't get updated.
mySurface[x, y].Set(255); // Will not work, i don't get an error but the color don't get updated.
How can i solve this problem?

How can i solve this problem?
Well you could avoid creating mutable structs and exposing public fields, to start with. That's where the problem is coming from. Your code is effectively:
Color tmp = mySurface[x, y]; // Take a copy from the array...
tmp.Set(255); // This only affects the copy
To change the array, you'll need to call the setter on the indexer instead. For example:
Color tmp = mySurface[x, y];
tmp.Set(255);
mySurface[x, y] = tmp;
Assuming you actually have several values in your struct, it would be simpler if you'd make your struct immutable but provide methods that returned new values, just like DateTime.AddDays etc. Then you could write code like:
mySurface[x, y] = mySurface[x, y].WithRed(255);
Options if you really want to avoid using a setter:
Use ref return from C# 7: redefine your indexer to return a ref Color; although then you can't have a setter.
Make Color a class instead of a struct
Use a reference type inside Color, so you don't need to change the bits in the Color value itself. (This is really nasty - I'm not suggesting that.)

Structs are value types, so if you get it from the array by calling pixels[y,x], you will actually create a copy of the struct to change the field on.
See also Unable to Modify struct Members

Related

Explicit struct in C# requires double init of value

The following C# struct is used to represent a union of color components and the 32bit color value itself. The problem is that the compiler gives the error:
Error CS0171 Field 'Color.ARGB' must be fully assigned before control is returned to the caller
Is it possible to get rid of this error without initialize the data twice? Is this expected behavior of C#? If I init twice, will the JIT detect the dual init and only do the second one?
[StructLayout(LayoutKind.Explicit)]
public struct Color
{
public Color(byte r, byte g, byte b, byte a = 0xff)
{
ARGB = 0; // The init I shouldn't have to do
A = a;
R = r;
G = g;
B = b;
}
[FieldOffset(0)]
public byte B;
[FieldOffset(1)]
public byte G;
[FieldOffset(2)]
public byte R;
[FieldOffset(3)]
public byte A;
[FieldOffset(0)]
public uint ARGB;
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
}
Is it possible to get rid of this error without initialize the data twice?
Yes and no.
The supposition here is that the members are not already "initialized twice". When you get the new struct from the memory allocator -- either from the heap or the stack -- it will be automatically zeroed out.
As Naidu's answer notes, calling the default constructor indicates to the compiler "the runtime must zero this thing out if it is not already; I wish to assert that I am fine with any portion of the object not written to by the constructor being left in its default state ".
In practice, typically the jitter has already initialized to zero, so typically there is no extra initialization done. However, the behaviour that memory allocators automatically initialize state to zero is runtime-implementation-dependent. Similarly it is an implementation-dependent behaviour whether or not the jitter can optimize away the zero-out behaviour if it knows that every field is initialized.
There are subtleties here. Suppose for example the memory is not zeroed out because the jitter has deduced that your constructor writes every field. Now suppose a thread abort exception is thrown halfway through the constructor. Is it possible for another thread to observe the not-zeroed-out, not-written-by-you state of the object? What hellish behaviour might that wreak, if in fact it is possible? Give that some thought.
Is this expected behavior of C#?
Yes.
The compiler has no idea whatsoever that you're creating a type-unsafe union. It doesn't know the meanings of those attributes.
If I init twice, will the JIT detect the dual init and only do the second one?
There are many different jitters on many different platforms. If you want an answer to your question, try it on all of them with all possible configurations and see what happens.
Regardless, you are likely worrying about nothing important. Writing zeros into memory is pretty fast. Doing an unnecessary zero write is probably not the bottleneck in your program.
Look into below Microsoft link:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0843
It says,
To assign a value to an automatically-implemented property from a
constructor, you must first invoke the default constructor to create
the object.
Doing below change will resolve your issue. call default constructor.
public Color(byte r, byte g, byte b, byte a = 0xff):this()
{
A = a;
R = r;
G = g;
B = b;
}
Use System.Runtime.CompilerServices.Unsafe.SkipInit, available since .NET 5. It is supposed to actually skip zero-initialization for bytes you're going to initialize anyway:
public Color(byte r, byte g, byte b, byte a = 0xff)
{
Unsafe.SkipInit(out ARGB);
A = a;
R = r;
G = g;
B = b;
}

when to use the "new" keyword with structs in c#

I am working with GDI+ and need to create a Brush or Pen. In most cases I should use a "color Struct". Searching around I see two different styles: One is like this:
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
and the other is:
Color myColor;
myColor = Color.FromArgb(255,0,0);
Brush B2 = new SolidBrush(myColor);
Can anyone describe how can we use a Color without declaring an instance of the Struct with new operator that calls the default constructor.
All that is going on here is that the interesting constructor is non-public, and you must create the value via a static utility method. You can achieve the same thing trivially in your own code:
struct Indirect
{
private readonly int value;
private Indirect(int value)
{
this.value = value;
}
public static Indirect Create(int value)
{
return new Indirect(value);
}
}
struct Direct
{
private readonly int value;
public Direct(int value)
{
this.value = value;
}
}
class Program
{
static void Main()
{
var x = Indirect.Create(42);
var y = new Direct(42);
}
}
Sometimes the expected usage is that the caller uses new; sometimes the expected usage is that the caller gets handed values from a helper method. In the case of Color: the latter. In the case of SolidBrush: the former. Note that this can be the case for both struct and class types - that is not the distinguishing factor.
In the case of Color, there are actually many more fields than you see directly; for example, knownColor, name, state - separately to the ARGB values. Some colors are "known" (from pre-defined named lists); some colors are ad-hoc (from ARGB data). The way you get the color determines these additional values.
The constructors of the type System.Drawing.Color are private and internal, meaning you can't call them from your code.
You'll need to instantiate a color through the given static methods and properties it contains, like Color.FromArgb() or Color.White.
As for the comments, which now make the question clear: those methods and properties are static, which means you don't call them on an instance (new Color().White) but on the type (Color.White).
Judging from its behavior, the method
Color.FromArgb(int red, int green, int blue)
most probably calls
new Color()
in its implementation, i.e. it declares an instance of the struct Color with the new operator.
Both implementations are equal, however
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
is shorter. I'd rather use even shorter in the case
Brush B1 = new SolidBrush(Color.Red); // R = 255, G = 0, B = 0 is just "Red"
Note, that Brush is IDisposable, that's why it seems that you have put it
using (Brush B1 = new SolidBrush(Color.Red)) {
... // Working with brush
}

C# declaration of variable

I started my journey with C# but I realised that I have some problems with some basic information about memory when it comes to declaration of variables. See if I am correct.
int x; // I declared variable of type int, which name is x. Compiler will provide memory for it but we dont have known value of it.
x=10; // Now memory location is still the same but value now kept there is 10;
public struct Point {
public int x, y;
}
Now I define a struct named Point. Beacuse struct is a value type, it again has reserved memory for it on the computer. Howewer x and y have no value.
Now Point p1 = new Point(); // what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
Second short question. When I write a code like:
int x = 10;
Can I say that I created instance of class integer which value is 10 and name x;
I would be grateful for help.
// what is happening here? Struct is not a reference type. So is this just initialization of Point variable with the default constructor without assigning values to x and y?
No; there are 4 possible scenarios here:
a class: the memory space is wiped to all 0s, then any custom constructor is invoked, which may also involve field initializers
a struct called without a custom constructor: the memory space is wiped to all 0s
a struct called with a custom constructor: the custom constructor is required to assign all the fields
a struct variable used without ever calling a constructor: this is actually a thing, but the calling code must write to all the fields before they can do anything else with it; since most structs do not expose their fields, this rarely works
Second short question. When i write a code like:
int x = 10;
Can i say that i created instance of class integer which value is 10 and name x; I would be grateful for help.
Not really, because in C# terms, int is not a class (it might be in IL terms). Simply: you have declared a local variable of type int with name x and assigned it the value 10, if this is in a method. If this is a class field, then: you have declared a private instance field of type int named x with a field-initializer giving it the value of 10.
Incidentally, you should avoid public fields in general, and mutable fields on structs. You might prefer:
public struct Point {
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public Point(int x, int y) { this.x = x; this.y = y'; }
}
This will avoid a huge range of problems.
In C# the default struct constructor sets the struct memory to 0, effectively setting all variables to their default values.
In case of ints, it will be 0. For reference types, it will result in null.
(in other words, for any type T it will be default(T)).
Note that when you write a custom constructor in a struct, you must initialize all member fields.
When you write
int x;
this is similar to
Point p1 = new Point(); (considering Point structure is already defined)
in both the cases all integer variables will have default value of 0 and not null, which is is basically what is used in C# to denote 'nothing' and can be assigned only to reference types.
As well, in c# everything is a class, so when you write
int x = 10;
you are creating an instance of class Int32, though the run time will handle this as value type instead of ref type, as special case.
Same is true for other basic types like, Long, DateTime and few others

Practical differences between classes and structs in .net (not conceptual)?

Whenever I tried to search about differences between classes and structs in C# or .net, I ended up with the conceptual overview of the two things like value type or the reference type, where the variables are allocated etc. But I need some practical differences. I have found some like different behavior of assignment operator, having constructors etc. Can anybody provide some more practical differences which will be directly useful while coding? Like the things works with one but not with other or same operation showing different behavior. And some common mistakes regarding these two.
Also please suggest where to consider using a struct instead of a class. And where the structs should not be used.
Edit:
Do I have to call the constructor explicitly or just declaring a struct type variable will suffice?(Should I make it a new question?)
OK, here are a few specific, practical differences:
A variable can be null if it’s a class, but is never null if it’s a struct.
default(T) is null for a class, but for a struct actually constructs a value (consisting of lots of binary zeros).
A struct can be made nullable by using Nullable<T> or T?. A class cannot be used for the T in Nullable<T> or T?.
A struct always has a public default constructor (a constructor with zero parameters). The programmer cannot override this constructor with a custom implementation — it is basically “set in stone”. A class allows the programmer to have no default constructor (or a private one).
The fields in a class can have default values declared on them. In a struct they can’t.
A class can inherit from another class, but a struct cannot be declared to derive from anything (it implicitly derives from System.ValueType).
It makes sense to use a class in object.ReferenceEquals(), but using a struct variable will always yield false.
It makes sense to use a class in a lock() statement, but using a struct variable will cause very subtle failure. The code will not be locked.
On a 32-bit system, you can theoretically allocate an array of up to 536,870,912 references to a class, but for a struct you need to take the size of the struct into account because you are allocating actual instances.
Structs in a container can only be modified if the container is a built-in array:
struct Point { public int x, y; void Move(int dx, int dy) { x += dx; y += dy; } }
...
Point[] points = getPointsArray();
points[0].Move(10, 0) = 10;
// points[0].x is now 10 higher.
List<Point> points = getPointsList();
points[0].Move(10, 0);
// No error, but points[0].x hasn't changed.
For this reason, I strongly favour immutable structs:
Point Move(int dx, int dy) { return new Point(x + dx, y + dy); }
...
points[0] = points[0].Move(10, 0); // Always works.
General observation: classes are usually better. Structs excel when you want to hold small, conceptually atomic data structures such as Point, Complex (number), Rational, etc.
structs, as they are value types, are copied on assignment; if you create your own struct, you should make it immutable, see Why are mutable structs evil?
Sometimes you don't want what you're passing to be mutable, and since a mutable struct may just be pure evil, I'd steer clear of ever creating one :) Here's an example a situation:
class Version:
class AccountInfo {
public string OwnerName { get; set; }
public string AccountNumber { get; set; }
}
struct Version:
struct AccountInfo {
public string OwnerName;
public string AccountNumber;
}
Now picture you called a method like this:
public bool TransferMoney(AccountInfo from, AccountInfo to, decimal amount)
{
if(!IsAuthorized(from)) return false;
//Transfer money
}
A struct is a Value type, meaning a copy gets passed into the method. The class version means a reference gets passed into the method, you wouldn't want for example the account number to be changeable after the authorization passed, you want nothing to be changed in an operation like this...you want an immutable value type. There's another question here asking why mutable structs are evil...any operation where you wouldn't want anything affected by the reference object changing, would be a practical place where a struct may fit better.
The example above may be somewhat silly, but the point is any sensitive operation where the passed in data shouldn't change in another thread or by any means really would be a place you look at passing by value.
Where they are allocated (heap vs. stack) is not something you really care about while you use them (not that you should disregard this - you should by all means study the differences and understand them).
But the most important practical difference you will come across the first time you decide to replace your class with a struct, is that structs are passed by value, while class instances are passed by reference.
This means that when you pass a struct to a method, a copy of its properties is created (a shallow copy) and your method actually gets a different copy than the one you had outside the method. When you pass an instance of a class, only a reference to the same place in memory is passed to the method, and your method is then dealing with exactly the same data.
For example, if you have a struct named MyStruct, and a class named MyClass, and you pass them to this method:
void DoSomething(MyStruct str, MyClass cls)
{
// this will change the copy of str, but changes
// will not be made to the outside struct
str.Something = str.Something + 1;
// this will change the actual class outside
// the method, because cls points to the
// same instance in memory
cls.Something = cls.Something + 1;
}
when the method ends, your class' property will be incremented, but your struct's property will remain unchanged, because str variable inside the DoSomething method does not point to the same place in memory.
The singularly important practical difference is that structs are value types, whereas classes are reference types. That has a few implications.
First of all, structs are copied on assignment. These two code blocks will have a different result (please note, normally you should neither use public fields nor mutable structs, I'm doing this for demonstration purposes only):
struct X
{
public int ID;
public string Name;
}
X x1 = new X { ID = 1, Name = "Foo" };
X x2 = x1;
x2.Name = "Bar";
Console.WriteLine(x1.Name); // Will print "Foo"
class Y
{
public int ID;
public string Name;
}
Y y1 = new Y { ID = 2, Name = "Bar" };
Y y2 = y1;
y2.Name = "Baz";
Console.WriteLine(y1.Name); // Will print "Baz"
X and Y are exactly the same, except that X is a struct. The results of this are different because every time we assign an X, a copy is made, and if we change the copy then we aren't changing the original. On the other hand, when we assign the contents of y1 to y2, all we've done is copied a reference; both y1 and y2 refer to physically the same object in memory.
The second consequence of structs being value types is generic constraints. If you want to pass in value types, the name of the constraint is literally "struct" or "class":
public class MyGeneric<T>
where T : struct
{ ... }
The above will let you create a MyGeneric<int> or MyGeneric<X>, but not a MyGeneric<Y>. On the other hand, if we change it to where T : struct, we're no longer allowed to create either of the first two, but MyGeneric<Y> is okay.
Last but not least, you need to use structs when writing interop, because with structs you're able to guarantee a specific arrangement in memory.
The link Tejs provided (http://www.jaggersoft.com/pubs/StructsVsClasses.htm) is a good explanation (although it is a bit out of date, particularly on the explanation of events).
The most import practical difference is that a struct is a value type, meaning it is passed by value rather than by reference. What this really means is that when a struct is passed as an argument, it is actually passed by copy. As a result, operations on one instance of a struct do not affect other instances.
Consider the following code:
struct NumberStruct
{
public int Value;
}
class NumberClass
{
public int Value = 0;
}
class Test
{
static void Main()
{
NumberStruct ns1 = new NumberStruct();
NumberStruct ns2 = ns1;
ns2.Value = 42;
NumberClass nc1 = new NumberClass();
NumberClass nc2 = nc1;
nc2.Value = 42;
Console.WriteLine("Struct: {0}, {1}", ns1.Value, ns2.Value);
Console.WriteLine("Class: {0}, {1}", nc1.Value, nc2.Value);
}
}
Because both ns1 and ns2 are of the NumberStruct value type, they each have their own storage location, so the assignment of ns2.Number does not affect the value of ns1.Number. However, because nc1 and nc2 are both reference types, the assignment of nc2.Number does affect the value of nc1.Number because they both contain the same reference.
[Disclaimer: The above code and text taken from Sams Teach Yourself Visual C# 2010 in 24 Hours]
Also, as others have already pointed out, structs should always be immutable. (Yes, in this example the struct is mutable but it was to illustrate the point.) Part of that means that structs should not contain public fields.
Since structs are value types, you cannot inherit from a struct. You also cannot derive a struct from a base class. (A struct can implement interfaces, however.)
A struct is also not allowed to have an explicitly declared public default (parameterless) contstructor. Any additional constructors you declare must completely initialize all of the struct fields. Structs also cannot have an explicitly declared destructor.
Since structs are value types, they shouldn't implement IDisposable and shouldn't contain unmanaged code.
Here's an interesting link: http://www.jaggersoft.com/pubs/StructsVsClasses.htm
For the most part though, there isn't much of a compelling reason to use structs when classes offer far more to the developer.

Not able to modify object of struct in loop

I have a List of structure.In the loop i am trying to modify the object's property,which is happening,but when i (Quick look in Visual studio)look into the list object ,the new value is not reflecting.Is it by virtue that the structure's object cannot be modified when in a collection?
I am using generics list with the struct as the type in the list
You mention "modify the object's property" in the context of a struct, but importantly a struct is not an object. Other people have answered as to the issue with structs being copied (and changes discarded), but to take that further the real problem here is that you have a mutable (changeable) struct at all. Unless you are on XNA (or similar) there is simply no need.
If you want to be able to change properties, make it a class:
public class Foo {
public string Bar {get;set;}
}
This is now a reference-type, and your changes (obj.Bar = "abc";) will be preserved through the foreach. If you really want/need a struct, make it immutable:
public struct Foo {
private readonly string bar;
public string Bar { get {return bar; }}
public Foo(string bar) {this.bar = bar;}
}
Now you can't make the mistake of changing the value of a copy; you would instead have to use the indexer to swap the value (list[i] = new Foo("abc");). More verbose (and you can't use foreach), but correct.
But IMO, use a class. Structs are pretty rare, to be honest. If you aren't sure: class.
If you are using a foreach loop you probably got
Compiler Error CS1654
Error Message Cannot modify members of
'variable' because it is a 'read-only
variable type'
This error occurs when you try to
modify members of a variable which is
read-only because it is in a special
construct.
One common area that this occurs is
within foreach loops. It is a
compile-time error to modify the value
of the collection elements. Therefore,
you cannot make any modifications to
elements that are value types,
including structs.
You could however try
struct MyStruct
{
public int i;
}
List<MyStruct> list = new List<MyStruct>
{ new MyStruct { i = 1 }, new MyStruct { i = 2 } };
for(int i = 0; i < list.Count; i++)
{
MyStruct val = list[i];
val.i++;
list[i] = val;
}
EDIT
See also Structs Tutorial
Structs vs. Classes
Structs may seem similar to classes,
but there are important differences
that you should be aware of. First of
all, classes are reference types and
structs are value types.
I THINK i know what the problem might be.
struct Astruct
{
int amember;
}
List < Astruct > listofStructs;
foreach(Astruct A in listofStructs)
{
A.amember = 1337;
}
if this is what you are doing...
when you use structs in c# they are not referenced but copied! so that means the contents of your list is being COPIED to A, so when you change A it doesn't change the value in the list!
to solve this problem (if this is your problem...) either use CLASSES rather than STRUCTS, that way A would be a reference, OR use a manual iterating for loop instead, ie:
for(int i=0;i < listofStructs.Count;i++)
{
listofStructs[i].amember = 1337;
}
alternatively, if you’re using a list, you maybe should use an iterator or something... but the above should definitely fix that problem.
Given the information in your post (although I'd have liked to see the code itself), let me put forth the most probable issue and its fix.
foreach(var s in listOfStructs)
{
s.Property = x;
}
s is assigned to a copy of the actual struct in the collection. s.set_Property is now modifying the copy which is thrown away at the end of the current iteration.
This is because 2 value type variables cannot point to the same instance.
struct1 = new MyStruct(100, 200);
struct2 = struct1; // struct2 is now a copy of struct1
Now to the problem of how do you modify the instances in a collection:
Get the object to modify in a local variable (copy created). Modify it. Now remove the original object and insert the copy. use listOfStructs[i] = modifiedInstance.

Categories

Resources