Value doesn't change when using a struct in a class - c#

Recently, I found a post on Internet asking this question, I tried to figure out but not sure.
I guess the problem is related with Boxing and Unboxing:
public readonly object counter = new Counter();
This line boxs a Counter onto heap, and counter refers to it.
((Counter)riddle.counter)
This line unboxs the Counter from heap.
Every time data it unboxs from heap is same as origin. Therefore, Line A doesn't affect Line B because they both retrieve from heap and are two different instances of Counter.
Is that right? Sorry for my poor English.
public void WantToKnow()
{
var riddle = new Riddle();
((Counter)riddle.counter).Increment(); // Line A
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
// Why the output is 0?///////////////////
}
struct Counter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}

Firstly, this is all a good example of why I try to avoid mutable structs in almost all cases. While you can usually predict what will happen if you pay enough attention, it's easy to miss one copy along the way which messes everything up. If you keep all structs immutable, life is simpler.
For your question: yes, you're unboxing which creates a copy of the counter. Changing that copy doesn't affect anything else. (There's IL to unbox without copying, but C# never uses that.)
You can make this work by making your counter implement an interface with an Increment operation. At that point you can cast to the interface instead of the value type, which means it's not unboxing. Your Increment operation would then modify the value within the box, which means you can then get at it again. Here's a complete example:
using System;
class Program
{
static void Main()
{
var riddle = new Riddle();
((ICounter)riddle.counter).Increment();
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
}
}
interface ICounter
{
void Increment();
}
struct Counter : ICounter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}

Because struct is value type- You can use "class Counter instead "struct Counter"
or use below solution
Reason : ((Counter)riddle.counter).Count is treat as another copy of struct not as ref type. so it's showing initial value 0
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var riddle = new Riddle();
Console.WriteLine(((Counter)riddle.counter).Increment());
///////////////////////////////////////////
Console.WriteLine(((Counter)riddle.counter).Count);
// Why the output is 0?///////////////////
}
}
struct Counter
{
private int x;
//Change is here
public int Increment() { this.x++; return this.x; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}

Related

Assigning locals to references to readonly fields (C# equivalent of "const &")

I've got a struct stored in a readonly field, nested in a few levels of objects (all in code that is outside of my control), that I am accessing in a function. For example:
struct Surprise { public readonly int a, b, c; }
struct Gizmo { public readonly Surprise surprise; }
struct Bobble { public readonly Gizmo gizmo; }
struct Thing { public readonly Bobble bobble; }
class Gift { public readonly Thing thing; }
void Function (Gift gift) {
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
}
Purely to avoid having to type out gift.thing.bobble.gizmo.surprise every time I use it, I'd like to assign that to a local variable with a shorter name. However, I also don't need to copy the struct, so I'd like to avoid that:
void Function (Gift gift) {
{ // (A) this is what i'm trying to not type out:
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
}
{ // (B) i can do this, but i don't *need* to copy, so i'd like to avoid:
Surprise s = gift.thing.bobble.gizmo.surprise;
int contrived = s.a * s.b + s.c;
}
{ // (C) what i *want* to do is something like this:
ref Surprise s = ref gift.thing.bobble.gizmo.surprise;
int contrived = s.a * s.b + s.c;
}
}
However, it seems that variation (C) there is not allowed, and so doesn't compile:
CS0192 A readonly field cannot be used as a ref or out value
(except in a constructor)
My question is: Is there a way to create a local variable that refers to a readonly value-typed field and doesn't copy it (or some other approach to save myself some typing)?
I'm fairly new to C#, coming from C++. If you're familiar with C++ I'm essentially looking for the equivalent of:
const Surprise &s = gift->thing.bobble.gizmo.surprise;
Also: Would it even make a difference, or is the compiler smart enough to not create a copy in (B) above?
By the way, I did, after much struggle, come up with this nightmare:
delegate void Hack (in Surprise s);
void Function (Gift gift) {
((Hack)((in Surprise s) => {
int contrived = s.a + s.b + s.c;
...;
}))(gift.thing.bobble.gizmo.surprise);
}
I'm not interested in that as an option, though, for hopefully obvious reasons. Also I'm not actually sure if that even avoids a copy.
How about an extension method.
public static class GiftExtension
{
public static int Sum(this Gift gift)
{
int contrived = gift.thing.bobble.gizmo.surprise.a +
gift.thing.bobble.gizmo.surprise.b +
gift.thing.bobble.gizmo.surprise.c;
return contrived;
}
public static int Sum(this Surprise surprise)
{
int contrived = surprise.a +
surprise.b +
surprise.c;
return contrived;
}
}
then in your method, you can have
void Function(Gift gift)
{
{
//(A) was trying to use a pointer to access the memory location, couldn't get it to work!
//unsafe
//{
// Surprise* ps = &(gift.thing.bobble.gizmo.surprise);
//}
}
//(B)
{
int contrived = gift.Sum();
}
{
int contrived = gift.thing.bobble.gizmo.surprise.Sum();
}
}
Create a readonly property to access the value you want.
public struct Surprise
{
get
{
return gift.thing.bobble.gizmo.surprise;
}
}

How to reuse a box?

I'm writing some memory-sensitive code where for various reasons I must box some value types. Moreover, after some warm-up, I need net new heap allocations to be 0. After I've boxed N values, my algorithm needs no more storage, but these values must be updated frequently. I would like to be able to reuse the boxes already created on the heap.
The following code suggests that boxes aren't reused (I can imagine why not). Is there different technique where I can reuse each box?
using System;
public class Program
{
public static void Main()
{
object x = 42;
object y = x;
x = 43;
bool isSameBox = Object.ReferenceEquals(x, y);
Console.WriteLine("Same box? {0}.", isSameBox);
}
}
// Output: "Same box? False."
My solution was to introduce an explicit reference type to be the reusable box.
public class ReusableBox<T> where T : struct
{
public T Value { get; set; }
public ReusableBox()
{
}
public ReusableBox(T value)
{
this.Value = value;
}
public static implicit operator T(ReusableBox<T> box)
{
return box.Value;
}
public static implicit operator ReusableBox<T>(T value)
{
return new ReusableBox<T>(value);
}
}

Access object of a class from other classes

I realise this is probably a very simple question and will be answered in no time. But wondering what to do. I have a class called Budget with an object named 'user01' I would basically like to be able to access that object across multiple classes, similar to the code below.
Main
static void Main(string[] args)
{
Budget user01 = new Budget(1000);
}
Budget Class
class Budget
{
private int _budget;
public Budget(int budget)
{
_budget = budget;
}
public int UserBudget
{
get { return _budget; }
set { _budget = value; }
}
}
Expense Class
class Expenses
{
// What I've been trying to do...
public int Something(user01.budget)
{
user01.budget - 100;
return user01.budget;
}
}
I'm not really sure where to go from here, and am hoping to a little help/explanation. Many thanks
This is invalid:
public int Something(user01.budget)
But you can supply an instance of a Budget object to that method:
public int Something(Budget budget)
{
budget.UserBudget -= 100;
return budget.UserBudget;
}
Then you can invoke that method from your consuming code:
Budget user01 = new Budget(1000);
Expenses myExpenses = new Expenses();
int updatedBudget = myExpenses.Something(user01);
The method doesn't "access the variable user01". However, when you call the method, you supply it with your user01 instance. Inside of the method, the supplied instance in this case is referenced by the local budget variable. Any time you call the method and give it any instance of a Budget, for that one time that instance will be referenced by that local variable.
Go ahead and step through this using your debugger and you should get a much clearer picture of what's going on when you call a method.
(Note that your naming here is a bit unintuitive, which is probably adding to the confusion. Is your object a "budget" or is it a "user"? Clearly defining and naming your types and variables goes a long way to making code easier to write.)
Its a pretty simple change to your Expenses class:
class Expenses
{
// What I've been trying to do...
public int Something(Budget userBudget)
{
userBudget.UserBudget -= 100;
return userBudget.UserBudget;
}
}
Which you then call like this from your main class:
static void Main(string[] args)
{
Budget user01 = new Budget(1000);
Expenses expenses = new Expenses();
var result = expenses.Something(user01);
}
Or, if you make your Something method static you can call it without an instance:
class Expenses
{
// What I've been trying to do...
public static int Something(Budget userBudget)
{
userBudget.UserBudget -= 100;
return userBudget.UserBudget;
}
}
Which you call like this:
static void Main(string[] args)
{
Budget user01 = new Budget(1000);
var result = Expenses.Something(user01);
}
Its important when designing methods to remember that a method takes in a general argument and its the caller that passes in something specific.

Creating a copy of an object in C# [duplicate]

This question already has answers here:
How do you do a deep copy of an object in .NET? [duplicate]
(10 answers)
Closed 3 years ago.
Please have a look at the code below (excerpt from a C# book):
public class MyClass
{
public int val;
}
public struct myStruct
{
public int val;
}
public class Program
{
private static void Main(string[] args)
{
MyClass objectA = new MyClass();
MyClass objectB = objectA;
objectA.val = 10;
objectB.val = 20;
myStruct structA = new myStruct();
myStruct structB = structA;
structA.val = 30;
structB.val = 40;
Console.WriteLine("objectA.val = {0}", objectA.val);
Console.WriteLine("objectB.val = {0}", objectB.val);
Console.WriteLine("structA.val = {0}", structA.val);
Console.WriteLine("structB.val = {0}", structB.val);
Console.ReadKey();
}
}
I understands it produces the output below:
objectA.val = 20
objectB.val = 20
structA.val = 30
structB.val = 40
The last two lines of the output I have no problem with, but the first two tell me that objectA and objectB are pointing to the same memory block (since in C#, objects are reference types).
The question is how do make objectB, a copy of objectA so that it points to a different area in memory. I understand that trying to assign their members may not work since those members may be references, too. So how do I go about making objectB a completely different entity from objectA?
You could do:
class myClass : ICloneable
{
public String test;
public object Clone()
{
return this.MemberwiseClone();
}
}
then you can do
myClass a = new myClass();
myClass b = (myClass)a.Clone();
N.B. MemberwiseClone() Creates a shallow copy of the current System.Object.
There is no built-in way. You can have MyClass implement the IClonable interface (but it is sort of deprecated) or just write your own Copy/Clone method. In either case you will have to write some code.
For big objects you could consider Serialization + Deserialization (through a MemoryStream), just to reuse existing code.
Whatever the method, think carefully about what "a copy" means exactly. How deep should it go, are there Id fields to be excepted etc.
The easiest way to do this is writing a copy constructor in the MyClass class.
Something like this:
namespace Example
{
class MyClass
{
public int val;
public MyClass()
{
}
public MyClass(MyClass other)
{
val = other.val;
}
}
}
The second constructor simply accepts a parameter of his own type (the one you want to copy) and creates a new object assigned with the same value
class Program
{
static void Main(string[] args)
{
MyClass objectA = new MyClass();
MyClass objectB = new MyClass(objectA);
objectA.val = 10;
objectB.val = 20;
Console.WriteLine("objectA.val = {0}", objectA.val);
Console.WriteLine("objectB.val = {0}", objectB.val);
Console.ReadKey();
}
}
output:
objectA.val = 10
objectB.val = 20
There's already a question about this, you could perhaps read it
Deep cloning objects
There's no Clone() method as it exists in Java for example, but you could include a copy constructor in your clases, that's another good approach.
class A
{
private int attr
public int Attr
{
get { return attr; }
set { attr = value }
}
public A()
{
}
public A(A p)
{
this.attr = p.Attr;
}
}
This would be an example, copying the member 'Attr' when building the new object.

C# compiler error: "cannot have instance field initializers in structs"

I need advice on structures.
I have 2 sections of code. The first section is as below:
namespace Project.GlobalVariables
{
class IOCard
{
struct InputCard
{
public string CardNo;
public int BaseAddress;
public int LowerAddress;
public int UpperAddress;
public int[] WriteBitNo = new int[16];
public int[] ReadBitNo = new int[16];
}
static InputCard[] InputCards = new InputCard[5];
public static string ACardNo = InputCards[1].CardNo;
public static string BCardNo = InputCards[2].CardNo;
}
}
The second portion is as below:
private void Form1_Load(object sender, EventArgs e)
{
IOCard.ACardNo = "Card A";
IOCard.BCardNo = "Card B";
MessageBox.Show(IOCard.ACardNo);
MessageBox.Show(IOCard.BCardNo);
}
My plan is to be able to assign and retrieve InputCards component by using IOCard as shown in Form1_Load.
However, when I compile the code, I get the following error.
Error 1 'Project.GlobalVariables.IOCard.InputCard.WriteBitNo': cannot have instance field initializers in structs E:\Programming\New platform\StandardPlatform\StandardPlatform\Project\GlobalVariables.cs 16 26 StandardPlatform
Can someone tell me how to solve the error?
Please advise. Thanks.
Here are the classes that I have attempted to create and use, but failed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Project.GlobalVariables
{
static class IOCard
{
public const int TotalInputCard = 10;
public const int TotalOutputCard = 10;
public class InputCard
{
public string CardNo = "1";
public int BaseAddress;
public int LowerAddress;
public int UpperAddress;
public int[] WriteBitNo = new int[16];
public int[] ReadBitNo = new int[16];
}
public class OutputCard
{
public string CardNo;
public int BaseAddress;
public int LowerAddress;
public int UpperAddress;
public int[] WriteBitNo = new int[16];
public int[] ReadBitNo = new int[16];
}
public static InputCard[] InputCards = new InputCard[TotalInputCard];
public static OutputCard[] OutputCards = new OutputCard[TotalOutputCard];
public static int X100 = InputCards[0].WriteBitNo[0];
public static int Y100 = OutputCards[0].WriteBitNo[0];
}
}
I tried to use these in the Form_Load, like so:
private void Form1_Load(object sender, EventArgs e)
{
IOCard.X100 = 1;
IOCard.Y100 = 1;
}
No matter how much I have tried to search on the net for answers, I have got nowhere.
Please advise. Thanks.
In C#, a struct value is not a reference to an object in the way a value of a class type is. The value of a struct is the "union" of all the values of the instance fields of the struct.
Now, the default value of a struct type is the value where all those fields have their default values. Since the beginning of C#, the syntax:
new S() // S is a value-type
where S is a struct type, has been equivalent to the default value of that struct. There is no constructor call! This is the exact same value which can (nowadays) also be written
default(S) // S is a value-type
Now, things like
struct S
{
int field = 42; // non-static field with initializer, disallowed!
// ...
}
are illegal (cannot have instance field initializers in structs). They could give the impression that the field of a new S() would be 42, but in fact the field of new S() must be the default value of int (which is zero, distinct from 42).
With this explanation, you also see why it is not possible to create a non-static, zero-parameter constructor for a struct type, in C#.
What's it's trying to say is that when you have InputCards = new InputCard[5]; it will allocate a block of memory 5 times the size of an InputCard structure and set all of its bytes to 0. There is no opportunity to execute the int[] WriteBitNo = new int[16]; and such assignments, so you cannot have them.
Your options are to either manually call an initializer for your structs or make it a class and manually initialize the InputCards array with 5 new instances of InputCard.
You will neither be able to initialize a struct's fields nor define a default constructor to initialize it's fields. After looking at your struct, I recommend you use a class instead. It's not recommended to use a struct for a scenario where you have a bunch of fields.
Try this. Initialize the InputCard with a factory function Create():
namespace Project.GlobalVariables
{
class IOCard
{
struct InputCard
{
public string CardNo;
public int BaseAddress;
public int LowerAddress;
public int UpperAddress;
public int[] WriteBitNo;
public int[] ReadBitNo;
static InputCard Create()
{
return new InputCard()
{
CardNo = string.Empty,
WriteBitNo = new int[16],
ReadBitNo = new int[16]
};
}
}
static InputCard[] InputCards = new InputCard[]
{
InputCard.Create(),
InputCard.Create(),
InputCard.Create(),
InputCard.Create(),
InputCard.Create()
};
public static string ACardNo = InputCards[1].CardNo;
public static string BCardNo = InputCards[2].CardNo;
}
}
Use class instead of structure. Structure is used for small types like Point, which are faster to create on the stack and copy, than to create dynamically and pass by reference.
Not sure about the exception, but i have a solution.
You should not use "struct" for this class, it is too much (and storing too much data). If you define it as "class", the same code would work fine.
Is there a particular reason why you want this to be a struct rather than a class?
If you make it a class, it works just fine.

Categories