How to automatically update a variable member of a class? - c#

I defined a class in C# that has a variable member (for example x1). How can I link x to a variable outside of class (for example x2) such that anytime that x2 changes the variable x1 automatically gets updated?
class Point
{
int x1;
}
void Main()
{
int x2;
Point p = new Point();
P.x1=x2;
}

The problem is that int is not a reference type, hence, it's always copied by value.
To trivially accomplish what you seek, simply wrap the value in a reference type:
public class X
{
public int value;
}
public class Point
{
public X x1;
}
void Main()
{
X x2 = new X();
Point p = new Point();
p.x1 = x2;
x2.value = 50;
Console.WriteLine(p.x1.value); //Prints out 50
}

as Matias said, since int values are not reference types, you can't update both simultaneously
Another way to solve the problem is to wrap your value into a class and use a
setter property
class Point
{
Point(Wrapped wrapped) {
_wrapped = wrapped;
}
private Wrapped _wrapped;
private int _x1;
public int x1 {
get { return _x1; }
set {
_x1 = value;
_wrapped.x2 = value;
}
}
}
class Wrapped {
int x2;
}
Now your main method will look like
void Main()
{
var wrapped = new Wrapped();
Point p = new Point(wrapped);
P.x1= 3;
Assert.AreEquals(p.x1, wrapped.x2); // true - both are equals to 3
}
disadvantage is that now both objects are coupled.

Related

anything like pointers in c#?

I'm new to c# (& coding in general) and i can't find anything pointer equivalent.
When i searched google i got something like safe/unsafe but that's not what i needed.
Like in c++ if you had a pointer and it pointed towards some value, the change in the pointer would cause change in the original variable.
Is there anything of such in c#?
example-
static class universal
{
public static int a = 10;
}
class class_a
{
public void change1()
{
universal.a--;
}
}
class class_b
{
public void change2()
{
some_keyword temp = universal.a; //change in temp gives change in a
temp-= 5; //the purpose of temp is to NOT have to write universal.a each time
}
}
...
static void Main(string[] args)
{
class_b B = new class_b();
class_a A = new class_a();
A.change1();
Console.WriteLine(universal.a);//it will print 9
B.change2();
Console.WriteLine(universal.a);//it will print 4
Console.ReadKey();
}
Edit-
thank you #Sweeper i got the answer
i had to use ref int temp = ref universal.a;
If you don't want unsafe code, I can think of two options.
Wrapper object
You can create a class like this, that wraps an int:
public class IntWrapper {
public int Value { get; set; }
}
Then change a's type to be this class:
static class Universal
{
public static IntWrapper a = new IntWrapper { Value = 10 };
}
class class_a
{
public void change1()
{
universal.a.Value--;
}
}
class class_b
{
public void change2()
{
Universal temp = universal.a; //change in temp gives change in a
temp.Value -= 5;
}
}
This works because classes are reference types, and a holds a reference (similar to a pointer) to a IntWrapper object. = copies the reference to temp, without creating a new object. Both temp and a refers to the same object.
ref locals
This is a simpler way, but it is only for local variables. You can't use this for a field for example.
public void change2()
{
ref int temp = ref universal.a; //change in temp gives change in a
temp -= 5;
}
C# has references which are very similar to pointers. If a and b are both references to the same object, a change in a will also be seen in b.
For example, in:
class X {
public int val;
}
void Main()
{
var a = new X();
var b = a;
a.val = 6;
Console.WriteLine(b.val);
}
6 will be written.
If you change the declaration of X from class to struct, then a and b will no longer be references, and 0 will be written.
In c# Pass By Reference is used instead of pointers, Here's the corrected code
static class universal
{
public static int a = 10;
}
class class_a
{
public void change1()
{
universal.a--;
}
}
class class_b
{
public void change2(ref int val)//use ref keyword for reference
{
int temp = val; //change in temp gives change in a
val -= 5;
}
}
static void Main(string[] args)
{
class_b B = new class_b();
class_a A = new class_a();
A.change1();
Console.WriteLine(universal.a);//it will print 9
B.change2(ref universal.a); //pass value by reference using ref keyword
Console.WriteLine(universal.a);//it will print 4
Console.ReadKey();
}
In some cases (when an optimization is very needed) you can use almost C-like pointers. You can only do that by explicitly specifying you are aware of the risk by placing your code in unsafe scope:
unsafe
{
int number = 777;
int* ptr = &number;
Console.WriteLine($"Data that pointer points to is: {number} ");
Console.WriteLine($"Address that pointer holds: {(int)ptr}");
}
The unsafe context allows you to use pointers directly. Please note that by default this option is turned off from your project. To test this you would need to right-click on project>Properties>Build - Allow unsafe code
Like this?
using System;
namespace Demo
{
class Program
{
static void Main()
{
var test = new class_a();
test.change1();
Console.WriteLine(universal.a); // Prints 18
}
}
static class universal
{
public static int a = 10;
}
class class_a
{
public void change1()
{
ref int x = ref universal.a;
++x;
++x;
++x;
x += 5;
}
}
}
[EDIT: I noticed that this is the same as the last part of Sweeper's answer, but I'll leave this here since it focusses just on that solution.]

Why do the properties in my code not work?

I have created an interface and then derived a class from it:
public interface Ishape
{
void draw();
int Number { get; set; }
}
class Circle : Ishape
{
public Circle(int a)
{
number = a;
}
public void draw()
{
Console.WriteLine("Circle.");
}
private int number;
public int Number
{
get
{
return number;
}
set
{
if (value < -5)
number = -5;
}
}
public int GetNumber()
{
return number;
}
}
class Program
{
static void Main(string[] args)
{
Circle a1 = new Circle(-6);
Console.WriteLine(a1.GetNumber());
Console.ReadLine();
}
}
As you can see, there is an autoproperty in the interface. I then decided to create a property in the new class that derived from the interface that would set the variable "number" to -5 if the value is less than -5. For some reason, the property does not seem to be working. Using the constructor, I set the value of the variable to -6, and the property did not change the value to -5. Why?
This is because you are setting number = a and not Number = a in your constructor. Try this:
public Circle(int a)
{
Number = a;
}
Your Number Property is never actually set.
In your Circle constructor, change number to Number.
public Circle(int a)
{
Number = a;
}
Also, if you intend to use GetNumber as your publicly available get (and nothing more), then I would advise that you change the access modifier for your Number property in your Circle class.

Object passed to method not maintaining reference in C#

I am trying to build a dummy exercise for my own interest.
I have one form (form1) with two textboxes (textBox1, textBox2) and a button.
When I click the button, I want to add the numbers passed to the textboxes.
Now, I am trying to complicate things by introducing an Interface with the signatures of the appropriate methods to do the addition (ICalculate) and a class (Calculations) which implements the interface.
Then I have another class called Calc which gets initiated from Form1 by passing an ICalculate object and 2 integers (a,b) in its constructor.
Furthermore, the Calc class has a method (addition()) for adding the two integers, using the ICalculate object and the two integers instantiated at the constructor of the class and display the result on a messagebox.
The problem is that the compiler throws an error saying that the ICalculate object has not been initialized (Object reference not set to an instance of an object.)
The code is the following:
public interface ICalculate
{
int add(int x, int y);
int sub(int x, int y);
}
class Calculations : ICalculate
{
public int add(int a, int b)
{
return (a + b);
}
public int sub(int z, int k)
{
return (z - k);
}
}
class Calc
{
private ICalculate _nc;
private int _x, _y;
public Calc(ICalculate nc, int a, int b)
{
var _nc = nc;
_x = a;
_y = b;
}
public void addition()
{
MessageBox.Show(_nc.add(_x, _y).ToString());
}
}
}
The Form1 Code is the following:
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var a = Int32.Parse(textBox1.Text);
var b = Int32.Parse(textBox2.Text);
var c = new Calc(new Calculations(), a, b);
c.addition();
}
}
Any help appreciated !
The problem is in the constructor of the Calc class.
Specifically, this row:
var _nc = nc;
You should remove the var:
_nc = nc;
What happens is that once you have the var keyword you are actually creating a local variable called _nc in the constructor, and assign the value of nc to it, so the class member called _nc is never initialized.
The compiler (tested on VS 2013) should issue a warning for this:
Field '<your namespace here>.Calc._nc' is never assigned to, and will always have its default value null

Unity C# how to make one variable equal another without using static keyword

So I have a basic problem in unity:
public int A = 0;
int B = A;
This code throws an 'A field initializer cannot reference the nonstatic field, method, or property' error.
So I could do this:
public static int A = 0;
int B = A;
Which works, but then variable 'A' will not show up on the inspector. Can I have my cake and eat it too, having both a variable that can equal another and having it show up in the inspector? Thank you.
public int A = 0;
public int B;
void Start() {
B = A;
}
Solutions that could have worked in C#:
public const int A = 9;
int B = A;
And
public static int A = 9;
int B = A;
Static and constant variables cannot be displayed in Unity Editor. If you want to assign A to B, and still make it to show in the Editor, you have to do this in a function.
If you want B to always have the-same value as A throuout the program runtime,
public int A;
int B;
//Initialize A to B
void Start()
{
B = A;
}
//Make B always equals to A
void Update()
{
B = A;
}
Because the class is not static, your fields will not be initialized until you actually create an instance of the class for example.
public class Bot
{
public int a = 0;
public int b;
//If you try this it will not work
//public int b = a;
public Bot()
{
//This will work because once you create Bot, all fields will be initialized
this.b = a;
}
}
public static void Main()
{
//Once you create the class the Bot constructor will be called automatially
Bot botty1 = new Bot();
}

c# parameter passing in ref with class field [duplicate]

This question already has answers here:
Is it possible to pass properties as "out" or "ref" parameters?
(3 answers)
Closed 7 years ago.
I want to swap the field in the ConvexHull class just like swap( points[0], points[1] ).
How do I have to do?
public class ConvexHull
{
List<Point> points;
public void run ()
{
Point.swap ( ref points[ 0 ], ref points[ 1 ] ); //Error!!
}
}
public class Point
{
private double x, y;
Point () { x = y = 0; }
public static void swap(ref Point a, ref Point b) {
Point c = a;
a = b;
b = c;
}
}
When you index an element of List<T> you are actually accessing the this indexer, which is a kind of property (i.e. has getter and setter methods). You can only pass variables as ref or out, not properties.
In your scenario, perhaps you want something more like this:
public class ConvexHull
{
List<Point> points;
public void run ()
{
swap(0, 1); //No error!!
}
private void swap(int i, int j)
{
Point point = points[i];
points[i] = points[j];
points[j] = point;
}
}
A more general solution might look like this:
public class ConvexHull
{
List<Point> points;
public void run ()
{
points.SwapElements(0, 1);
}
}
static class Extensions
{
public static void SwapElements<T>(this List<T> list, int index1, int index2)
{
T t = list[index1];
list[index1] = list[index2];
list[index2] = t;
}
}
In either case, the correct approach is to provide the code that is actually swapping values with access to the List<T> object itself, so that it can access the indexer property to accomplish the swap.
Throw pretty much all of that away. You can't pass properties or list objects by ref. I notice there is nothing initially populating those points. Populate your List of Points, then call a function in your ConvexHull class to SwapPoints(int point1idx, int point2idx) and write the code there to do the swap.
On the Point class, expose X and Y, and drop the swap routine from there as it will never work.

Categories