I have a question. When I do a
Int32 ii = new Int32();
am I creating a value type of a reference type with the identifier "ii?" If I'm creating a reference type, then how is it that when I pass a copy of that reference to a method that changes it's value, I don't see the changes when the method returns? When I run the code below I get "0."
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Int32 ii = new Int32();
changeit(ii);
Console.WriteLine(ii.ToString());
Console.ReadLine();
}
static void changeit (Int32 i)
{
i = 2;
}
static void changeit(ref int i)
{
i = 2;
}
}
}
The new operator has a different meaning for value and reference types. For reference types, it means to allocate on the heap and initialize the type; for value types it means initialize only. So
int i=new int();
is the same as
int i=0;
See C# reference as a starter.
If I'm creating a reference type
You aren't creating a reference type. Using new doesn't change value type to a reference type.
static void Main(string[] args)
{
Int32 ii = new Int32();
changeit1(ii);
Console.WriteLine(ii.ToString());
changeit2(ref ii);
Console.WriteLine(ii.ToString());
Console.ReadLine();
}
static void changeit1(Int32 i)
{
i = 2;
}
static void changeit2(ref int i)
{
i = 2;
}
Results:
0
2
Int32 is by definition a value type. A type can be a value type or reference type by definition, you can't change it.
If you want your Int32 to be modified, you should pass it with the "ref" keyword:
static void changeit(ref int i)
{
i = 2;
}
The only way to acomplish something like that is encapsulating your Int32 inside a class, like:
public class DumbClass{
public int YourInt {get; set;}
}
When you put your integer as a property, you can change it, sending your DumbClass reference:
static void changeit(DumbClass c)
{
c.YourInt = 2;
}
This happens because classes are reference types (by definition).
Inside the hood, a lot of things happens. The framework may decide to allocate your variable in the stack or the heap depending os it's mood (because sometimes optimizations happens).
Usually when you declare an int inside a method, it's allocated on the stack and since it will be deallocated when the method finishes it's execution, it will be pretty weird if it is a reference type.
That's why there's the "boxing" and "unboxing" inside the framework. Sometimes value types are "boxed" so you can use it as reference types (and allocated on the managed heap). Personally, I don't know if there's a way to do it explicitly in C# and if it makes sense.
Related
I'm programming in C# about 2 months, and I've been noticing to the fact that the only way a method will get a parameter by reference is when the method sets as a static method, and I don't understand the reason behind this situation. As example, in C++ we could just send parameters by reference to any kind of method we wanted to.
Thanks ahead :)
I'm adding a very simple code for those who asked for:
public void f(ref int num)
{
num++;
}
private static void Main(string[] args)
{
int a = 0;
f(ref a);
Console.WriteLine(a);
Console.Read();
}
the error I get:
An object reference is required for the non-static field, method, or property
now, I know that in C# almost everything that not int, string, double... and other built-in vars are send automatically by ref. I wonder why the method must be static in case of sending those vars by ref.
the only way a method will get a parameter by reference is when the method sets as a static method
That's incorrect. C# has a concept of Reference Types and Value Types, where both are passed by value, but that value differs. For reference types, the value that gets passed is the reference itself, where for value types it's a copy of the value.
If you want a value type by reference, you can use the ref modifier in the methods signature:
public void M(ref int x)
Same goes for reference type, only for the fact that passing them by ref will pass the current reference pointing to the data structure, and won't create a copy of that reference.
You are not able to use f because it's an instance method and the Main is a static one so you cannot call it from here without having an instance of the class that contains f (I guess Program).
You need to either create an instance of Program:
this is exaclty the same as what the error message says:
An object reference is required for the non-static field, method, or property
so you create an object reference to Program:
class Program
{
public void f(ref int num)
{
num++;
}
private static void Main(string[] args)
{
int a = 0;
var p = new Program();
p.f(ref a);
Console.WriteLine(a);
Console.Read();
}
}
or make the method static to be able to use it:
class Program
{
public static void f(ref int num)
{
num++;
}
private static void Main(string[] args)
{
int a = 0;
f(ref a); // is the same as: Program.f(ref a)
Console.WriteLine(a);
Console.Read();
}
}
The ref keyword has nothing to do with it. It's all about how you call the method - via an object reference or as a static one without an object reference. Neither is better then the other. It's a design decision and each serves different puposes.
I have something interesting that I want to understand little deeper.
I have an extension class that extends int:
public static class MyExtension
{
public static void GetProp(this int i, MyObject o)
{
var val = i;
o.sum = i;
}
}
That uses a class as one of its parameter:
public class MyObject
{
public int sum { get; set; }
}
Now, lets see the unit test class:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void test()
{
int a = 1;
int b = 2;
int sum = 0;
Add(a, b, sum);
//Here, sum=3 but after its execution, sum looses its value and
retains the value sum = 0
int test = 4;
MyObject obj = new MyObject();
test.GetProp(obj);
But in the above code when I pass the variable using the extension
method, the obj.sum retains its value obj.sum = 4 . I am not passing any
value by reference. The first portion of code seems to follow the
passing ByVal. But the second portion of extension method, the value
is retained as if its passed as ByRef
string s = sum.ToString();
string p = obj.sum.ToString();
}
private void Add(int x, int y, int sum)
{
sum = x + y;
}
}
Can someone explain the mechanism behind this. Thanks
All parameters are send by value, unless you specify them with the ref or out keyword. Passing a parameter by value means that the value is copied.
However, when you pass an object by value it's not the object that is copied, it's the reference that is copied. That means that you have two references to the same object, one in the obj variable and one in the o parameter, but only one object.
When the extension method accessed the object, it's the same object as outside the method. Any change to the property made using the o parameter will be visible when you later access it using the obj variable.
This is the difference between passing by reference and passing a reference object (class). In GetProp, you aren't modifying the reference obj, you are modifying the MyObject instance that is referred by obj.
If I understand your question, you're confused about why the sum variable isn't changed when it is passed by value, but the obj.sum property does retain its value when obj is passed by reference. The other answers do a good job of explaining this.
In your question, you pass a parameter by value as a receiver, and this confuses your question a bit. Your question appears to be, "why is it that when I pass normally, it's treated as by-value, but when I pass as a receiver to an extension method, it's by-reference?"
Ah. Try assigning a new value to the receiver and see what happens at the call site:
public static void GetProp(this int i, MyObject o)
{
o.sum = i;
i = 5000;
}
You'll find that the variable test at the call site is not affected by this, since the receiver is also passed by value!
Can I use an out parameter with a recursive method? If it's possible, how can I do it with the following code?
private void PrepareDir(out List<_File> listFiles,string root,string dirPath) {
DirectoryInfo dirRoot = new DirectoryInfo(dirPath);
FileInfo [] Files = dirRoot.GetFiles();
dirPath = dirPath.Substring(root.Length);
foreach (FileInfo file in Files) {
_File _file = new _File();
_file.Name = dirPath + "\\" + file.Name;
_file.Path = file.FullName;
_file.Size = file.Length;
listFiles.Add(_file);
}
foreach (DirectoryInfo dir in dirRoot.GetDirectories()) {
PrepareDir(out listFiles, root, dir.FullName);
}
}
private void btnButton1_Click(object sender, EventArgs e) {
List<_File> Files = new List<_File>();
PrepareDir(out Files,currAddress, currAddress);
}
I decided to rewrite my answer to be more direct about why using out is not necessary here. I wrote this to be rather lengthy, because I think the root of your question is more in not understanding the differences between passing by value, passing by reference, and the common confusion between a reference type being passed by reference. Also note that this isn't explicit to only recursion.
In C#, reference types are passed by value by default. A lot of people can confuse a reference type with passing by reference, but there is an important difference. To make myself more clear, I will refer to a reference type as is, and passing by reference as using the ref or out keywords.
Passing a reference type by value, because it is a reference to some storage location in memory, allows you to make and persist changes. Take this example.
public class MyRefType
{
public int Value { get; set; }
}
public void Foo() {
MyRefType type = new MyRefType();
AddOne(type);
}
public void AddOne(MyRefType type) {
type.Value++;
}
What will happen here, is that the class type will now have a value of one. This is the nature of a reference type. If type were a struct, it would still have a value of 0 inside the Foo method, because a copy was made instead of holding a reference to the object.
Now that I hope you understand the symantics of passing a reference type by value, let's actually talk about passing a reference type by reference. This is done using the out and ref keywords. Make it a point to note immediately that in the CLR, out technically does not exist, only ref does. out is actually represented in metadata as ref with a special attribute applied to it, and they ought to be treated the same.
Now let's say we wanted to re-assign our reference type in the AddOne method before doing the addition.
public class MyRefType
{
public int Value { get; set; }
}
public void Foo() {
MyRefType type = new MyRefType();
AddOne(type);
}
public void AddOne(MyRefType type) {
type = new MyReferenceType();
type.Value++;
}
Because we are still passing our reference type by value, the value of type in the method Foo will still be 0. All we did was initialize another storage location in memory, instead of reassigning the original storage location). But we want to actually pass our reference type by reference, so we should really do:
public class MyRefType
{
public int Value { get; set; }
}
public void Foo() {
MyRefType type = new MyRefType();
AddOne(ref type);
}
public void AddOne(ref MyRefType type) {
type = new MyReferenceType();
type.Value++;
}
Now the value of type in the Foo method will be 1. This is because we reused the same storage location that the reference pointed to, instead of creating a new location in memory.
So how does all this apply to out? Remember that out is the same as ref with different usage symantics. The difference is that with ref you may leave the method without the reference being initialized, whereas with out, you must explicitly initialize it before the method returns.
So in your case of using out here, it is completely not necessary because you already have existing reference symantics working for you. I hope this clears up a bit.
You are misusing the keyword out in your code example. Your List<_File> is passed as a reference type, and any changes made to that list will affect the caller's list. You only need to pass an out parameter when you want to reassign the caller's identifier.
Consider:
public bool Foo()
{
List<int> list = new List<int>();
list.Add(1);
Bar(out list);
return list.Contains(1);
}
public void Bar(out List<int> list)
{
list = new List<int>();
list.Add(2);
}
Foo would return false.
If, on the other hand, Bar was like this:
public void Bar(List<int> list)
{
list = new List<int>();
list.Add(2);
}
Then Foo would return true. See out for more details.
Your code would work as is without the use of out. And, in fact, would not compile - and to make it compile would increase unnecessary complexity to what you are trying to do. Don't use out in your case.
I was wondering how one could store a reference to an object in .net.
That is, I would like something like the following code (note, of course, that the following code may be way off from how to actually do it):
class Test
{
private /*reference to*/ Object a;
public Test(ref int a)
{
this.a = a;
this.a = ((int)this.a) + 1;
}
public Object getA() { return this.a; }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(ref a);
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
To produce the following output:
4
4
Ideally, I would like to do this without writing a wrapper class around the integer.
In other words, I think I want pointers in .Net.
You cannot store references to variables in .NET, period. You can store references to objects, but not references to variables.
The reason is that if you were allowed to store references to arbitrary variables then you could store references to local variables. If you can store references to local variables then the runtime cannot use the optimization of storing local variables on the short-lived memory pool, aka, the stack.
Now, even if you could do that, the operation you are describing is not typesafe for a different reason. You have a (very badly named) field variable "a" of type "reference to object variable" and a (very badly and confusingly named) local variable "a" of type "reference to int variable". Even if you could store a reference to a variable it doesn't make any sense to store a reference to an int variable in something of type "reference to object variable" because those two types are logically not compatible. The operations you can perform on them are different; a reference to an object variable can have a string written into it; a reference to an int variable cannot.
Perhaps I am misunderstanding but wouldn't a variable such as the integer above be boxed into an object which could then be stored as a reference?
You are confusing references to objects with references to variables. It is confusing that we use the same terminology for what is really two different things.
Yes, boxing turns a value type, like int, into a reference type, like object. That has ABSOLUTELY NOTHING WHATSOEVER to do with references to variables.
When you make a ref to a variable you are making an alias for that variable. When you say
void M(ref int y) { y = 123; }
...
int x = 0;
M(ref x);
you are saying "x and y are two different names for the same variable".
Now, if what you want to do is represent the notion of "I have captured a variable and I want to be able to read and write it" then use delegates:
class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
int abc = 123;
var refabc = new Ref<int>(()=>abc, x=>{abc=x;});
... now you can pass around refabc, store it in a field, and so on
refabc.Value = 456;
Console.WriteLine(abc); // 456
Console.WriteLine(refabc.Value); // 456
Make sense?
C# has no concept of a reference variable akin to C++'s int& a. There are workarounds. One is to use closures:
class Test
{
private Func<int> get_a;
private Action<int> set_a;
public Test(Func<int> get_a, Action<int> set_a)
{
this.get_a = get_a;
this.set_a = set_a;
this.set_a(this.get_a() + 1);
}
public Object getA() { return this.get_a(); }
}
/*
* ...
*/
static void Main(string[] args)
{
int a;
a=3;
Test t = new Test(() => a, n => { a = n; });
Console.WriteLine(a);
Console.WriteLine(t.getA());
Console.ReadKey();
}
I'm not in front of VS, so please excuse any embarrassing faux pas.
If I am passing an object to a method, why should I use the ref keyword? Isn't this the default behaviour anyway?
For example:
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t.Something = "Bar";
}
}
public class TestRef
{
public string Something { get; set; }
}
The output is "Bar" which means that the object was passed as a reference.
Pass a ref if you want to change what the object is:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
After calling DoSomething, t does not refer to the original new TestRef, but refers to a completely different object.
This may be useful too if you want to change the value of an immutable object, e.g. a string. You cannot change the value of a string once it has been created. But by using a ref, you could create a function that changes the string for another one that has a different value.
It is not a good idea to use ref unless it is needed. Using ref gives the method freedom to change the argument for something else, callers of the method will need to be coded to ensure they handle this possibility.
Also, when the parameter type is an object, then object variables always act as references to the object. This means that when the ref keyword is used you've got a reference to a reference. This allows you to do things as described in the example given above. But, when the parameter type is a primitive value (e.g. int), then if this parameter is assigned to within the method, the value of the argument that was passed in will be changed after the method returns:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
You need to distinguish between "passing a reference by value", and "passing a parameter/argument by reference".
I've written a reasonably long article on the subject to avoid having to write carefully each time this comes up on newsgroups
In .NET when you pass any parameter to a method, a copy is created. In value types means that any modification you make to the value is at the method scope, and is lost when you exit the method.
When passing a Reference Type, a copy is also made, but it is a copy of a reference, i.e. now you have TWO references in memory to the same object. So, if you use the reference to modify the object, it gets modified. But if you modify the reference itself - we must remember it is a copy - then any changes are also lost upon exiting the method.
As people have said before, an assignment is a modification of the reference, thus is lost:
public void Method1(object obj) {
obj = new Object();
}
public void Method2(object obj) {
obj = _privateObject;
}
The methods above does not modifies the original object.
A little modification of your example
using System;
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t = new TestRef();
t.Something = "Bar";
}
}
public class TestRef
{
private string s;
public string Something
{
get {return s;}
set { s = value; }
}
}
Since TestRef is a class (which are reference objects), you can change the contents inside t without passing it as a ref. However, if you pass t as a ref, TestRef can change what the original t refers to. i.e. make it point to a different object.
With ref you can write:
static public void DoSomething(ref TestRef t)
{
t = new TestRef();
}
And t will be changed after the method has completed.
Think of variables (e.g. foo) of reference types (e.g. List<T>) as holding object identifiers of the form "Object #24601". Suppose the statement foo = new List<int> {1,5,7,9}; causes foo to hold "Object #24601" (a list with four items). Then calling foo.Length will ask Object #24601 for its length, and it will respond 4, so foo.Length will equal 4.
If foo is passed to a method without using ref, that method might make changes to Object #24601. As a consequence of such changes, foo.Length might no longer equal 4. The method itself, however, will be unable to change foo, which will continue to hold "Object #24601".
Passing foo as a ref parameter will allow the called method to make changes not just to Object #24601, but also to foo itself. The method might create a new Object #8675309 and store a reference to that in foo. If it does so, foo would no longer hold "Object #24601", but instead "Object #8675309".
In practice, reference-type variables don't hold strings of the form "Object #8675309"; they don't even hold anything that can be meaningfully converted into a number. Even though each reference-type variable will hold some bit pattern, there is no fixed relationship between the bit patterns stored in such variables and the objects they identify. There is no way code could extract information from an object or a reference to it, and later determine whether another reference identified the same object, unless the code either held or knew of a reference that identified the original object.
This is like passing a pointer to a pointer in C. In .NET this will allow you to change what the original T refers to, personally though I think if you are doing that in .NET you have probably got a design issue!
By using the ref keyword with reference types you are effectively passing a reference to the reference. In many ways it's the same as using the out keyword but with the minor difference that there's no guarantee that the method will actually assign anything to the ref'ed parameter.
ref mimics (or behaves) as a global area just for two scopes:
Caller
Callee.
If you're passing a value, however, things are different. You can force a value to be passed by reference. This allows you to pass an integer to a method, for example, and have the method modify the integer on your behalf.