I am learning C# memory management and faced weird to me thing.
I dynamically allocate memory for Student object and change it in a method — it is being changed.
I dynamically allocate memory for int object and change it in a method — it isn't being changed.
Why??
class Student
{
public int id;
public string name;
}
class Program
{
static void Main(string[] args)
{
Student s1 = new Student();
s1.id = 5;
s1.name = "myname";
ChangeStud(s1);
Console.WriteLine(s1.id);
Console.WriteLine(s1.name);
int x = new int();
x = 2;
ChangeInt(x);
Console.WriteLine(x);
}
static void ChangeStud(Student s)
{
s.id = 500;
s.name = "changedname";
}
static void ChangeInt(int x)
{
x = 500;
}
}
The output is:
500changedname2
Passing a class object by value is similar to passing a pointer to a data structure in a non-object-oriented language, because what is actually passed is the memory location of the object. Since that address is given, the memory to which the address refers can be modified.
Passing a scalar variable value such as an integer is just passing a value. The called method doesn't receive the memory location of the int, just a copy of the value. Any changes will not modify the value in the original memory location.
The problem is that you are changing the int in the ChangeInt method but the parameter is copied not referenced you can either use the ref keyword or return the value of the method:
static void ChangeInt(ref int x)
{
x = 500;
}
or
static int ChangeInt(int x)
{
return 500;
}
If you use the later method remember to catch the value
Related
I have a class with just one variable
public class C
{
int i;
}
And in another project file I create an array of classes
C[] classes = new C[100000];
So what i need to do to set some random value to the "i" variable in each class?
First you need to make C.i accessible. One way is to make C.i a public property. While you’re at it, public fields should be pascal cased and all identifiers should have meaningful names.
When naming public members of types, such as fields, properties, events, methods, and local functions, use pascal casing.
public class Foo {
public int Bar { get; set; }
}
Then you'd use System.Random. Instantiate it once and call Random.Next each time you want a random number.
using System;
var rand = new Random();
// int anyPositiveInt = rand.Next();
// int positiveIntLessThanFifteen = rand.Next(15);
// int intFromOneToFour = rand.Next(1, 5);
Finally, following the example in Creating N objects and adding them to a list, use System.Linq's Enumerable.Range, Enumerable.Select, and Enumerable.ToArray as follows:
Foo[] classes = Enumerable
.Range(0, 100000)
.Select(_ => new Foo { Bar = rand.Next() })
.ToArray();
If the requirement is to use a private field then I recant the earlier advice to make it a public property - properties might not have been taught yet
static void Main()
{
var r = new Random();
var maxValueOfI = 100;
var minValueOfI = -20;
var csArr = new C[100000];
for (var julius = 0; julius < csArr.Length; julius++) {
var brutus = r.Next(minValueOfI, maxValueOfI+1);
csArr[julius] = new C(brutus);
}
}
public class C
{
private int _i;
public C(int i){
_i = i;
}
}
So, what's going on here?
The main addition is a constructor to C. A constructor is a special method that is called by C# when a new object is constructed. Every class has one even if you can't see it (the compiler provides one if you don't). Constructors are methods that are intended to ensure the class is fully set up and ready to use. Because it's inside the class it has full access to all the data fields of the class:
public C(int i){
_i = i;
}
This constructor takes an int, and sets the private field _i to the value of the passed in number. It's quite common to use this naming pattern for fields (prefix with underscore) and it helps avoid a name collision with the arguments to the method (in this case called i). If they had both been called i the class one would have to be prefixed with this. and it's (IMHO) more clutter
This line of code calls the constructor:
csArr[julius] = new C(brutus);
We've previously calculated a random number between -30 and 100 (inclusive both ends) and stashed it in a variable called brutus. This number is passed to the constructor, which is called when we say new C. The resulting fully constructed C instance is stored in one of the array slots
try this
static void Main()
{
Random rand = new Random();
var max=100000;
C[] array = new C[max];
for (var i=0; i <max; i++)
array[i] = new C { Num = rand.Next(0, max)};
// or using a constructor
array[i] = new C (rand.Next(0, max));
}
public class C
{
public int Num {get; set;}
public C (int num)
{
Num=num;
}
public C (){}
}
First of all, in your current code i is a private field. Let's add a constructor to set this field:
public class C {
int i;
public C(int value) {
i = value;
}
}
Then you can try using Linq:
using System.Linq;
...
Random rand = new Random();
...
C[] classes = Enumerable
.Range(0, 100000)
.Select(i => new C(rand.Next(0, 100))) //TODO: Put the right range here
.ToArray();
static int GetCount(BinTreeNode<int> L)
{
int count = 0;
while (L != null)
{
count++;
L = L.GetRight();
}
return count;
}
I have the method GetCount().
Now, BinTreeNode is a class that has the members: right, left and info.
for some reason, in the main function
static void Main(string[] args)
{
var t2 = new BinTreeNode<int>(null, 1, new BinTreeNode<int>(null, 2, new BinTreeNode<int>(null, 3, null)));
//Console.WriteLine(TreeLessThanTree(t1, t2));
Console.WriteLine(GetCount(t2));
Console.WriteLine(t2.GetInfo()); // this prints 1
Console.ReadKey();
}
This is weird, since in the function GetCount(), L (which is passed by reference) is changed to null.
Why wasn't t2 passed by reference? Why didn't t2 change?
The reference is passed by value. Meaning: the value of t2 is essentially just a pointer that happens to be the address of an object; when it is passed by value, the pointer (i.e. 4 or 8 bytes) is copied and passed in. It doesn't matter what the GetCount does with the local copy of the pointer: the change to the pointer is not observed at the call-site. However, if the method changes the object at the end of the pointer, then those changes will be observable.
The object is passed in the method. Every changes done in the properties of that object will be kept.
However, if you set something else to the local variable in the method, the original object won't be changed. If you want to change the variable, you have to explicitely use the ref keyword.
In example :
public class A
{
public string Foo { get; set; }
}
public class Program
{
// This is a local variable. If you set something else to this one, the original won't be changed
// |
// V
public static void DoSomething(A a)
{
a.Foo = "42"; // <---- This changes the property in the original
a = new A // <---- This sets something to the local variable a
{
Foo = "Hello world"
};
}
// This variable is passed by references. If you set something else to this one, the original will be changed
// | |
// V V
public static void DoSomethingElse(ref A a)
{
a.Foo = "42"; // <---- This changes the property in the original
a = new A // <---- This sets something to the original
{
Foo = "Hello world"
};
}
public static void Main()
{
var a = new A
{
Foo = "Bar"
};
DoSomething(a);
Console.WriteLine(a.Foo); // This outputs 42
// notice this --v
DoSomethingElse(ref a);
Console.WriteLine(a.Foo); // This outputs Hello world
}
}
I am creating an anonymous method and passing it into an action to be invoked later on. I would like to pass some numeric data (int) into my anonymous method. In order to pass the data by value, am I required to create copies? Or, will the data be passed by value?
Here is what I think the implementation would look like, if I had to create copies:
private void CreateAction()
{
int bus = 4;
CustomObject[] data = new object[16];
int length = 1500;
this.doWorkLater = new Action(() =>
{
var busCopy = bus;
var dataCopy = data;
var lengthCopy = length;
this.WorkMethod(busCopy, dataCopy, lengthCopy);
});
}
Is this (the above code) necessary in order to get length and bus by value?
In this case, will CustomObject[] data (some class I have created) be passed by reference or by value?
What you pass is not a By-Value Copy.
If you're not going to modify the values before executing the action, then you don't need to worry about how you pass the values. But no they are no passed by value. Even if you return the action and Invoke it from another method. the values are persisted in a class generated by the compiler. No need to worry about that
If you expect the data to change before executing the action then you're doing it wrong. The approach you're using (Copy a Value-Type to a local variable) should be done outside the action and not inside of it. As for the reference type (Array) even if you copy it to a local variable, the reference it copied so any change in the copy local variable is reflected.
private void CreateAction()
{
int bus = 4;
CustomObject[] data = new object[16];
int length = 1500;
var busCopy = bus; // a copy of bus
var dataCopy = data; // reference copy
var lengthCopy = length; // a copy of length
this.doWorkLater = new Action(() =>
{
this.WorkMethod(busCopy, dataCopy, lengthCopy);
});
bus = 10; // No effect on the action
length = 1700; // No effect on the action
this.doWorkLater();
}
This looks pointless, but you may sometimes need to copy a local variable to another local variable before passing it to an anonymous method. Check this Valid Example that fixes a reported unexpected behavior !
Closures capture values observably by reference* - note that code you have does not solve issue for general case, also if whole point of CreateAction is create one single action it will work.
private void CreateAction()
{
int bus = 4;
this.doWorkLater = new Action(() =>
{
var busCopy = bus;
this.WorkMethod(busCopy);
});
// if you change local `bus` before call to `doWorkLater` it will not work:
bus = 42;
doWorkLater(); // busCopy is 42.
}
* It actually collects all variables in a compiler created class and uses reference to it to access variables in a method and closure. Thus even value types look behave as if passed by reference.
This might help you to figure out what's going on.
If you start with this slightly simplified class:
public class Example
{
private void CreateAction()
{
int bus = 4;
object[] data = new object[16];
int length = 1500;
Action doWorkLater = () =>
{
var busCopy = bus;
var dataCopy = data;
var lengthCopy = length;
this.WorkMethod(busCopy, dataCopy, lengthCopy);
};
doWorkLater.Invoke();
}
public void WorkMethod(int bus, object[] data, int length)
{
}
}
...then the compiler produces basically this:
public class Example
{
private void CreateAction()
{
Example.GeneratedClass closure = new Example.GeneratedClass();
closure.parent = this;
closure.bus = 4;
closure.data = new object[16];
closure.length = 1500;
// ISSUE: method pointer
IntPtr method = __methodptr(closure.CreateAction);
new Action((object)closure, method)();
}
public void WorkMethod(int bus, object[] data, int length)
{
}
[CompilerGenerated]
private sealed class GeneratedClass
{
public int bus;
public object[] data;
public int length;
public Example parent;
internal void CreateAction()
{
this.parent.WorkMethod(this.bus, this.data, this.length);
}
}
}
The local variables trapped in the closure cease being local variables to the method and become public fields in the generate class.
Now everything that you know about C# and classes applies.
I am trying to pass an array to a method. The array contains objects which need to be nulled. The method would simply null each object in a loop. I need this to reflect back in the caller.
Sample code (code goodness & minor syntactical issues can be ignored):
public class ABC
{
...
}
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
var arrayOfNullableObjects = new ABC[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
}
private void NullingFunction(ABC[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i] = null;
}
}
Clearly upon returning, toBeNulledObj1 & toBeNulledObj2 are not null but retain their older values though arrayOfNullableObjects now has two null objects. I realise that ref & out only apply to the collection parameter (here, arrayOfNullableObjects which doesn't even need a ref). I tried passing them in as params instead of a collection but that doesn't help, either (ref & params cannot be combined).
Question: How can I alter each/any object in a collection of objects within a method such that the change is visible to the caller? I am not altering the collection itself. Please note, I am not changing the contents/members of toBeNulledObj1 but the reference itself (to either null or a new object).
Solution #1: Unsafe code
One solution is using a unsafe code. You have to think twice before using it, and I do not know if you will be happy with my answer, but here it is.
static private void SomeMethod()
{
ABC toBeNulledObj1 = new ABC();
ABC toBeNulledObj2 = new ABC();
IntPtr[] arrayOfNullableObjects = new IntPtr[] { MakeReference(ref toBeNulledObj1), MakeReference(ref toBeNulledObj2) };
NullingFunction(arrayOfNullableObjects);
}
static private void NullingFunction(IntPtr[] arrayOfNullableObjects)
{
foreach (IntPtr reference in arrayOfNullableObjects)
ClearReference(reference);
}
/// <summary>
/// Makes the reference to the reference value of a reference type.
/// </summary>
static unsafe private IntPtr MakeReference<T>(ref T value)
where T: class
{
TypedReference reference = __makeref(value);
return *(IntPtr*)&reference;
}
/// <summary>
/// Clears the reference to a reference type, using a reference to that reference value.
/// </summary>
static unsafe private void ClearReference(IntPtr reference)
{
if (sizeof(IntPtr) == 4)
*((int*)reference) = 0;
else
*((long*)reference) = 0;
}
Solution #2: Anonymous class
The second solution could be done by using an anonymous class which holds your data. The fields inside this anonymous class are cleared. A disadvantage is that you have a second class and the reference to this class also should to be cleared. (This can be done by adding ref to o and in the NullingFunction set o to null.) Of course you can also use a predefined class, but his solution is the closest to your code in your OP.
public static void SomeMethod()
{
var container = new
{
toBeNulledObj1 = new ABC(),
toBeNulledObj2 = new ABC(),
};
NullingFunction(container);
}
private static void NullingFunction<T>(T container)
where T : class
{
if (container == null)
return;
foreach(FieldInfo f in container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
if (f.FieldType.IsClass)
f.SetValue(container, null);
}
When you say you want to set them to null, do you mean that you want to destroy the object?
C# has automatic garbage collection, so as soon as an object goes out of scope (that is, when no other objects make reference to it), the garbage collector will destroy it.
In the code above, the label "tobeNulledObj1" still refers to an object, and your array also points to it before you call the NullingFunction.
After you call the NullingFunction, you still have one reference pointing to the object (that is, tobeNulledObj1). If you set tobeNulledObj1 to null, then the Garbage Collector will collect it.
EDIT: I second cheedep's question - what is it exactly that you are trying to do? What do you want your variables to hold at the end?
If function A holds a reference to a variable i.e:
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
And does not pass this into function B:
private NullingFunction(ABC[] arrayOfNullableObjects)
Then there is nothing that function B can do to change the reference that toBeNulledObj1 / 2 points to.
Since ref is not allowed along with params (as you mentioned):
private void NullingFunction(ref params ABC[] arrayOfNullableObjects)
{
for (int i = 0; i < arrayOfNullableObjects.Length; i++)
{
arrayOfNullableObjects[i] = null;
}
}
The available alternative is to create overloads e.g.:
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
NullingFunction(ref toBeNulledObj1, ref toBeNulledObj2);
Console.ReadKey();
}
private void NullingFunction(ref ABC one)
{
one = null;
}
private void NullingFunction(ref ABC one, ref ABC two)
{
one = null;
two = null;
}
Is wrapping acceptable?
class Wrapped<T> where T : new() {
private T val = new T();
...
public void Nullify() { val = null; }
}
private void SomeMethod()
{
var toBeNulledObj1 = new Wrapped<ABC>();
var toBeNulledObj2 = new Wrapped<ABC>();
var arrayOfNullableObjects = new Wrapped<ABC>[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
Debug.Assert(toBeNulledObj1.Get() == null);
// Or...
Debug.Assert(toBeNulledObj1.IsDefined == false);
// Or...
Debug.Assert(toBeNulledObj1.IsNull == true);
}
private void NullingFunction(Wrapped<ABC>[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i].Nullify();
}
}
(Disclaimer: hand-compiled code :) may contain errors)
If you need it as a general pattern, you can make NullingFunction parametric (T, U), with a constaint where U: Wrapped<T>
The idea is to make something similar to Nullable for ref types, or something that looks like a smart pointer, if you are familiar with C++.
Thus, wrapper could have T Get() (or an implicit conversion to T) to get out the value, an IsDefined property, and so on.
Hey I want to have something like that
int a=0;
a=5(be unchangeable);
a=3;
Console.WriteLine(a);//which will print 5 and not 3
so basically make declare the variable a number and have it be final and unchangeable, I tried looking around but I only found things that work as the int is declared and not as a new value for it is declared.
doesn't this work?
const int a = 5;
see const(C# reference)
const int a = 0;
The const keyword is used to modify a declaration of a field or local
variable. It specifies that the value of the field or the local
variable is constant, which means it cannot be modified.
Ref.
You want the const keyword.
const int a = 5;
From MSDN:
The const keyword is used to modify a declaration of a field or local variable. It specifies that the value of the field or the local variable cannot be modified.
EDIT: Your requirement sounds odd and not useful. But if you really need it, you'll have to create a custom type. I'd suggest a class with a bool property stating whether or not it's mutable or not.
public class MyCustomInt
{
public bool IsMutable { get; set; }
private int _myInt;
public int MyInt
{
get
{
return _myInt;
}
set
{
if(IsMutable)
{
_myInt = value;
}
}
}
public MyCustomInt(int val)
{
MyInt = val;
IsMutable = true;
}
}
Then when you use it:
MyCustomInt a = new MyCustomInt(0);
a.MyInt = 5;
a.IsMutable = false;
a.MyInt = 3; //Won't change here!
Console.WriteLine(a); //Prints 5 and not 3
That's about as good as you can get, I think.
use readonly:
as it can be changed by the constructor but then not again.
public class MyClass {
private readonly int a = 0;
public MyClass(int a) {
this.a = a;
}
public void DoSomethingWithA() {
Console.WriteLine(this.a);
//a = 5 // don't try this at home kids
}
}
new MyClass(5).DoSomethingWithA();
A nice comparison between const and readonly
You can use a constant with the const keyword.
const int a = 5;
but if you do that, you will not be allowed to change to another value.
You also can check the use of the pointers:
int x = 5;
int y = 3;
int *ptr1 = &x; // point to x memory address
int *ptr2 = &y; // point to y memory address
Console.WriteLine(x); // print 5
Console.WriteLine(y); // print 3
Console.WriteLine((int)ptr1); // print 5
Console.WriteLine((int)ptr2); // print 3
Console.WriteLine(*ptr1); // print 5
Console.WriteLine(*ptr2); // print 3
* char identify a pointer and & specify the memory address. But you should take care with pointers because unlike reference types, pointer types are not tracked by the default garbage collection mechanism.