In C++, I have a function:
void MyFunction(int p)
{
p=5;
}
Assume, I have:
int x = 10;
MyFunction(x); // x = 10
MyFunction(&x); // x = 5
How to archieve this in C# with condition: I create only one MyFunction.
Your C++ function doesn't work the way you think it does. In fact, your code will not compile.
In C#, you would use the ref or out keywords:
void MyFunction1(out int p)
{
p = 5;
}
void MyFunction2(ref int p)
{
p = p + 1;
}
int x;
MyFunction1(out x); // x == 5
MyFunction2(ref x); // x == 6
In C# you would need to declare the method with a ref parameter, like this:
void MyFunction(ref int p)
{
p=5;
}
If you then call it as MyFunction(ref x) the value of x in the caller will be modified. If you don't want it to be modified simply copy it to a dummy variable. You could create an overload of MyFunction that does this internally:
void MyFunction(int p)
{
MyFunction(ref p);
}
It would technically not be "one function", as you want, but the code wouldn't be duplicated and to any human reading your code it would appear as one - but to the compiler it's two. You would call them like this:
int x = 10;
MyFunction(x); // x = 10
MyFunction(ref x); // x = 5
C# does not have the equivalent functionality. If you declare the method to have a ref parameter, then you must also specify that the parameter is ref type when you call the method.
You need to pass the parameter as reference. If you don't specify it, it automatically creates a copy to work inside the parameter instead of using the same reference.
How to do that? Just specify with the 'ref' word in method declaration:
void MyFunction(ref int p)
{
p=5;
}
int x = 10;
MyFunction(ref x); // x = 5
The point is that a lot of people think that Reference types are passed by reference and Value types are passed By Value. This is the case from a user's perspective, internally both Reference and Value types are passed By Value only.
When a Reference type is passed as a parameter, its value, which is a reference to the actual object is passed. In case of Value types, their value is the value itself (e.g. 5).
StringBuilder sb = new StringBuilder();
SetNull(sb);
SetNull(ref sb);
if SetNull(...) sets the parameter to null, then the second call will set the passed in StringBuilder parameter to null.
Related
I have seen a couple of the example on internet stated that I have to reset the stream by
stream.Seek(0, SeekOrigin.Begin);
However, if I pass the stream into a method as
public static bool ValidateStreamLine(Stream stream)
Do I have to still reset the stream?
Understand that on usual case if I pass in int, string, float or any other general variable type as
public static bool ValidateInt(int i)
the value of int i would not change.
Would that be any difference of the nature of Pass-by Value method on how the method react to stream?
You seem to be misunderstanding how arguments are passed in C#. By default, all arguments are passed by value in C#. In order to pass them by reference you need to use a special keyword: ref or out the latter being normally used when the argument is used as a second output of a given method. (See int.TryPase for example).
The important thing to understand here is that arguments passed by value behave quite diferently if the type of the argument is a reference type or a value type. This is where you seem to be confused.
To understand how it all works, make sure you are clear on the following:
Variables hold values.
The value of a variable whose type is a value type, is the value type's instance itself:
int i = 1 // i holds the value 1
The value of a variable whose type is a reference type is not the instance of said type. The value is the memory address where that instance lives.
string s = "Hello!" // s does not hold "Hello!" it holds a number that points to a place in memory where the string "Hello!" lives.
So, now that we are clear on that, what happens when you pass arguments by value (C#'s default)? What happens is that a copy of the variable is made and the copy is passed to the method.
If the type is a reference type, what is really copied and passed to the method is the value stored in the variable. And what is that? The memory address where the object referenced by the variable lives. So you see what happens? Both the original variable and the copied variable both point to the same object:
public class Foo
{
var frobbed = false;
public bool Frobbed { get { return frobbed; } }
public void Frob() { frobbed = true; }
}
void Frob(Foo foo) { foo.Frob(); }
var myFoo = new Foo();
Frob(myFoo);
Console.WriteLine(myFoo.Frobbed); //Outputs True! Why? Because myFoo and foo both point to the same object! The value of both variables (memory address) is the same!
If the type is a value type, the value itself of the value type is copied and handed to the method so there is no way the method can modify the value type stored in the original variable.
public void Increment(int i) { i = i + 1; }
var myInt = 1;
Increment(myInt);
Console.WriteLine(myInt); //Outputs 1, not 2. Why? i holds its own copy of 1, it knows nothing about the copy of 1 stored in myInt.
Things change when you pass arguments by reference. Now, the argument passed to the method is not a copy, its the original variable itself. A logical question follows; does this actually change anything in how reference types behave? The answer is yes, quite a lot:
public void ByValueCall(string s)
{
s = "Goodbye";
}
public void ByReferenceCall(ref string s)
{
s = "Goodbye";
}
var myString = "Hello!";
Console.WriteLine(ByValueCall(myString )); //outputs "Hello!"
Console.WriteLine(ByValueCall(myString )); //outputs "Goodbye!"
This behavior is identical with value types too. What is happening here?
When you pass an argument by value, the method gets a copy of the variable; therefore assigning a new value to the argument is really just assigning a new value to the copy; the original variable at the callsite doesn't care that you change the value of it's copy, be it a value type or a reference type. It will keep holding the value it always had.
When passing an argument by reference, you are not passing a copy, you are passing the variable itself. In that case assigning a new value to the variable will persist at the callsite. A canonical example is the following swap method:
public void Swap(ref int a, ref int b)
{
var temp = a;
a = b;
b = temp;
}
var i1 = 1;
var i2 = 2;
Swap(ref i1, ref i2);
var b = i1 == 2; //true
b = i2 == 1; //true
So after all of this, you should understand why the following behaves the way it does:
public ResetStream(Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
}
var myStream = new ...
myStream.Read(bytes, 0, 1024);
ResetStream(myStream);
var isAtOrigin = myStream.Position == 0; //Returns true!
I have been making an effort on C# methods. There are three ways that parameters can be passed to a C# methods.
Value parameters : This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.
Reference parameters : This method copies the reference to the memory location of an argument into the formal parameter. This means that changes made to the parameter affect the argument.
Output parameters : This method helps in returning more than one value.
I understood above types of passing parameters with below sample codes.
using System;
namespace PassingParameterByReference
{
class MethodWithReferenceParameters
{
public void swap(ref int x)
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
MethodWithReferenceParameters n = new MethodWithReferenceParameters();
/* local variable definition */
int a = 100;
Console.WriteLine("Before swap, value of a : {0}", a);
/* calling a function to swap the value*/
n.swap(ref a);
Console.WriteLine("After swap, value of a : {0}", a);
Console.ReadLine();
}
}
}
When the above code is compiled and executed, it produces the following result:
Before swap, value of a : 100
After swap, value of a : 5
With this codes i could understand to pass parameters to methods by reference. And then i examine below code to understand passing parameters to methods by output.
using System;
namespace PassingParameterByOutput
{
class MethodWithOutputParameters
{
public void swap(out int x)
{
int temp = 5;
x = temp;
}
static void Main(string[] args)
{
MethodWithOutputParameters n = new MethodWithOutputParameters();
/* local variable definition */
int a = 100;
Console.WriteLine("Before swap, value of a : {0}", a);
/* calling a function to swap the value */
n.swap(out a);
Console.WriteLine("After swap, value of a : {0}", a);
Console.ReadLine();
}
}
}
When the above code is compiled and executed, it produces the following result:
Before swap, value of a : 100
After swap, value of a : 5
These sample codes make same action with different ways. And i can't understand difference between two approaches.( Passing Parameters To Method By Output And By Reference). Two example's output is the same. What is this small difference?
Output parameters dont have to be initialized before the method is called like it is the case for reference parameters.
int someNum;
someMethod(out someNum); //works
someMethod(ref someNum); //gives compilation error
Furthermore, the Output parameter needs to be set or changed within the method, which is not necessary for reference parameters.
With "Reference" parameters, the value needs to be assigned before a method can use it. X and Y in your examples would have needed to have been declared outside the method.
e.g. int x = 100; int y =200;
With "Output" parameters, the value for your parameters don't have to be assigned a value before you can use them. X and Y could have been declared in your example with no starting values assigned to them.
e.g int x; int y;
Reference and Output parameters are very similar.
The only difference is that ref parameters must be initialized.
int myInt = 1;
SomeMethod(ref myInt); //will work
SomeMethod(out myInt); //will work
int myInt;
SomeMethod(ref myInt); //won't work
SomeMethod(out myInt); //will work
The compiler will actually view the ref and out keywords the same. For example if you cannot have overloaded methods where the only difference is the ref and out keywords.
The following methods signatures will be viewed the same by the compiler, so this would not be a valid overload.
private void SomeMethod(ref int Foo){};
private void SomeMethod(out int Foo){};
An output parameter needs to have it's value changed inside the method otherwise the compiler will throw an error.
The reference parameter may or may not have it's reference (reference objects) changed by the method.
Also value types (types defined in structs) cannot be passed by reference.
See this What's the difference between the 'ref' and 'out' keywords?
The difference is that for an out parameter you have to set it before leaving the method. So even if you dont set it to any value before calling the method the compiler knows that it will get a value during the method call.
Appart from technical differences, to have a good readable code, you should use out when the method has more than one output. And use ref when the method just may update the variable
I want a pass several variables to a function to and set them to something else instead of reading from them. I am planning to use this in a scenario where i can create a object, and add it to a execution queue. Would a pointer be right for this?
I am aware my question has a poor explanation, but I don't know a better way to explain it.
It sounds like you probably want a ref or out parameter. For example:
public static void SetVariables(out int x, ref int y)
{
// Can't *read* from x at all before it's set
x = 10;
// Can read and write y
y++;
}
public static void Foo()
{
int setOnly;
int increment = 5;
SetVariables(out setOnly, ref increment);
Console.WriteLine("{0} {1}", setOnly, increment); // 10 6
}
See my parameter passing article for more information.
Are these variables reference types or value types? If they are reference types then you can pass them into your function as per normal and then mutate its properties from there. If they are value types then you must use the ref keyboard.
I have some void methods which are static.
Is it better to pass variables by reference or by value, because I'm passing large amount of text into these variables :
public static void renderText(ref StringBuilder build)
{
//Do your job.
}
So could someone explain me, what happens when I send a reference of StringBuilder, does it only access this StringBuilder? (It does not copy it right!).
And just in case I'm not changing the value or any other property of input arguments into methods.
So, in this cases where variables are huge enough and not manipulated, should I always send the reference of it, and if yes does it interfere with something?
Take a look at the following article by Jon Skeet in which he thoroughly explains the difference between passing by reference or by value.
Parameter passing in C#
or this blog post which illustrates the former article:
http://rapidapplicationdevelopment.blogspot.com/2007/01/parameter-passing-in-c.html
The last article actually uses the StringBuilder type in its examples, so you can clearly see what's going on in your case. If you pass in the StringBuilder type by reference you'll get this:
Reference type passed by reference:
As long as you're dealing with reference types (classes, which StringBuilder and String are), there's rarely a point in passing them by reference since no copy will be made anyways.
Non-value types are always passed by reference. The purpose of ref keyword is to let you change the reference to the object inside the method.
You misunderstood the arguments passing completely. Read this article.
Passing arguments by value
By default, arguments in C# are passed by value. This means a copy of the value is created when passed to the method:
class Test
{
static void Foo(int p)
{
p = p + 1; // Increment p by one.
Console.WriteLine(p); // Write p to screen.
}
static void Main()
{
int x = 8;
Foo(x); // Make a copy of x.
Console.WriteLine(x); // x will still be 8.
}
}
Assigning p a new value does not change the contents of variable x, because p and x reside in different memory locations.
Passing a reference-tupe argument by value copies the reference, but not the object. An example in the case of string builder; here Foo sees the same StringBuilder object that main instantiated, but has an independent reference to it. So StrBuild and fooStrBuild are seperate variables that reference the same StringBuilder object:
class Test
{
static void Foo(StringBuilder fooStrBuild)
{
fooStrBuild.Append("testing");
fooStrBuild = null;
}
static void Main()
{
StringBuilder StrBuild = new StringBuilder();
Foo(strBuild);
Console.WriteLine(StrBuild.ToString()); // "testing"
}
}
Because fooStrBuild is a copy of a reference changing its value does not change StrBuild.
Pass by reference
In the following, p and x refer to the same memory locations:
class Test
{
static void Foo(ref int p)
{
p = p + 1; // Increment p by one.
Console.WriteLine(p); // Write p to screen.
}
static void Main()
{
int x = 8;
Foo(ref x); // Make a copy of x.
Console.WriteLine(x); // x is now 9.
}
}
hence the value of p is changed.
Hope this helps.
I have a doubt in scope of varibles inside anonymous functions in C#.
Consider the program below:
delegate void OtherDel(int x);
public static void Main()
{
OtherDel del2;
{
int y = 4;
del2 = delegate
{
Console.WriteLine("{0}", y);//Is y out of scope
};
}
del2();
}
My VS2008 IDE gives the following errors:
[Practice is a class inside namespace Practice]
1.error CS1643: Not all code paths return a value in anonymous method of type 'Practice.Practice.OtherDel'
2.error CS1593: Delegate 'OtherDel' does not take '0' arguments.
It is told in a book: Illustrated C# 2008(Page 373) that the int variable y is inside the scope of del2 definition.
Then why these errors.
Two problem;
you aren't passing anything into your del2() invoke, but it (OtherDel) takes an integer that you don't use - you still need to supply it, though (anonymous methods silently let you not declare the params if you don't use them - they still exist, though - your method is essentially the same as del2 = delegate(int notUsed) {...})
the delegate (OtherDel) must return an int - your method doesn't
The scoping is fine.
The error has nothing to do with scopes. Your delegate must return an integer value and take an integer value as parameter:
del2 = someInt =>
{
Console.WriteLine("{0}", y);
return 17;
};
int result = del2(5);
So your code might look like this:
delegate int OtherDel(int x);
public static void Main()
{
int y = 4;
OtherDel del = x =>
{
Console.WriteLine("{0}", x);
return x;
};
int result = del(y);
}