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.
Related
I have a value (struct instance) that was cast to object for generic handling. I need to make a copy of the value. I cannot do this explicitly because I just have its Type and don't know what it is in compile time.
By default I get a copy of reference: var copy = objectOfMyStruct;. I thought about making an explicit shallow copy by MemberwiseClone() but I cannot do this because it's protected method and I cannot modify MyStruct.
Convert.ChangeType(objectOfMyStruct, typeOfMyStruct) doesn't help because conversion (actually no conversion) happens inside and it returns Object again.
How could I do this?
EDIT:
I need to make a copy to preserve original value and just deserialized one to pass to OnChangeHandler. Simplified implementation is:
var oldValue = type.GetValue(reference);
var newValue = oldValue; // something better is needed here
Deserialize(type, stream, ref newValue);
OnChange(oldValue, newValue);
type.SetValue(reference, newValue);
Copy is made because only delta (changes) are sent so should be applied to the original value.
EDIT 2:
This implementation works fine for primitive types, so despite int is boxed too I'm copying it instead of copying reference to it. I just don't understand this.
Here is an example of what is needed.
This example, which you can test in LINQPad should make a clone of the struct without casting it back to its unboxed type, so that when it is mutated by a call through the implemented interface, only the original is mutated. The question is thus; how do I write that Clone method?
void Main()
{
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static object Clone(object input)
{
return input;
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
I assume that you not only want to make a copy, but also be able to actually use that copy.
And in order to use it, you need to cast (unbox) it to the appropriate type, which effectively makes a copy. In fact, even putting the value into the box already resulted in a copy.
So, if (for example) you know that these objects are either ints or floats, you could do:
if (obj is int)
{
int i = (int) obj;
// do something with the copy in i
}
else if (obj is float)
{
float f = (float) obj;
// do something with the copy in f
}
If you have a large number of types to evaluate, you can use a switch statement or even a Dictionary<Type,Action<object>>.
If you need to deal with types that you don't know about at compile time (some type added dynamically thorugh some kind of plugin mechanism) than this won't be possible, but then again, it would also not be possible to do anything with the object (unless through an interface).
UPDATE:
Now that you changed your question, here's a better answer: you do no need to make a copy, it has been made for you by boxing the struct.
Example:
int i = 42;
// make a copy on the heap
object obj = i;
// modify the original
i = i + 1;
// copy is not modified
Debug.Assert((int)obj == 42);
Obviously, I'm using int here for convenience, but it is true for every struct. If the struct implements an interface, you can cast the object to that interface (that won't make a second copy) and use it. It will not modify the orginal value, because it is operating on the copy in the box.
UPDATE 2:
Just to be very explicit: this works for every struct. For example:
interface IIncrementor
{
void Increment();
}
struct MyStruct : IIncrementor
{
public int i;
public void Increment()
{
this.i = this.i + 1;
}
public override string ToString()
{
return i.ToString();
}
}
// in some method:
MyStruct ms = new MyStruct();
ms.i = 42;
Console.Writeline(ms); // 42
object obj = ms;
IIncrementable ii = (IIncrementable) obj;
ii.Increment();
Console.Writeline(ms); // still 42
Console.Writeline(ii); // 43
One more UPDATE:
instead of
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
write
Dummy original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = original;
and you'll be fine.
Thanks for the LINQPad example, it greatly clarified your question and it gave me a starting point for coming up with a solution.
This is a very brute-force solution, but it might serve your purpose, until somebody comes up with a more elegant answer:
static object Clone(object input)
{
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(input));
try
{
Marshal.StructureToPtr(input, p, false);
return Marshal.PtrToStructure(p, input.GetType());
}
finally
{
Marshal.FreeHGlobal(p);
}
}
This is how it works:
It allocates unmanaged memory large enough to hold your struct.
StructureToPtr unboxes your input and copies it into unmanaged memory:
If structure is a value type, it can be boxed or unboxed. If it is boxed, it is unboxed before copying.
PtrToStructure creates a new structure, boxes it and returns it:
You can pass a value type to this overload method. In this case, the returned object is a boxed instance.
The unmanaged memory is freed.
Here's another answer:
static object Clone(object input) =>
typeof(object)
.GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(input, null);
It uses the Object.MemberwiseClone method. This method is protected, which is why I have to call it via reflection.
This approach works fine with enums, and with structs that have [StructLayout(LayoutKind.Auto)].
If the list of types to handle this cloning for is controlled, that is, you know which types you need to handle this for, then I would simply create a dictionary that contains functions that knows how to handle each particular type.
Here's a LINQPad example:
void Main()
{
_CloneMapping[typeof(Dummy)] = (object obj) =>
{
Dummy d = (Dummy)obj;
return new Dummy { Field = d.Field, Property = d.Property };
};
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static readonly Dictionary<Type, Func<object, object>> _CloneMapping = new Dictionary<Type, Func<object, object>>();
static object Clone(object input)
{
if (input == null)
return null;
var cloneable = input as ICloneable;
if (cloneable != null)
return cloneable.Clone();
Func<object, object> cloner;
if (_CloneMapping.TryGetValue(input.GetType(), out cloner))
return cloner(input);
throw new NotSupportedException();
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
This will output:
I am writing a "Monitor" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it possible in C# to store a reference to a value type? Say I have the following class:
class Test
{
public int a;
}
Can I somehow store a "pointer" to "a" in order to be able to check it's value anytime? Is it possible using safe and managed code?
Thanks.
You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.
(ASIDE: It is possible for C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))
However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.
sealed 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); }
}
}
...
Ref<string> M()
{
string x = "hello";
Ref<string> rx = new Ref<string>(()=>x, v=>{x=v;});
rx.Value = "goodbye";
Console.WriteLine(x); // goodbye
return rx;
}
The outer local variable x will stay alive at least until rx is reclaimed.
No - you can't store a "pointer" to a value type directly in C#.
Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a (via testInstance.a).
Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)
public interface IValuePointer<T>
{
T Value { get; set; }
}
public class ValuePointer<TParent, TType> : IValuePointer<TType>
{
private readonly TParent _instance;
private readonly Func<TParent, TType> _propertyExpression;
private readonly PropertyInfo _propInfo;
private readonly FieldInfo _fieldInfo;
public ValuePointer(TParent instance,
Expression<Func<TParent, TType>> propertyExpression)
{
_instance = instance;
_propertyExpression = propertyExpression.Compile();
_propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo;
_fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo;
}
public TType Value
{
get { return _propertyExpression.Invoke(_instance); }
set
{
if (_fieldInfo != null)
{
_fieldInfo.SetValue(_instance, value);
return;
}
_propInfo.SetValue(_instance, value, null);
}
}
}
This can then be used like so
class Test
{
public int a;
}
void Main()
{
Test testInstance = new Test();
var pointer = new ValuePointer(testInstance,x=> x.a);
testInstance.a = 5;
int copyOfValue = pointer.Value;
pointer.Value = 6;
}
Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.
You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)
You can create ref-return delegate. This is similar to Erik's solution, except instead of getter and setter it use single ref-returning delegate.
You can't use it with properties or local variables, but it returns true reference (not just copy).
public delegate ref T Ref<T>();
class Test
{
public int a;
}
static Ref<int> M()
{
Test t = new Test();
t.a = 10;
Ref<int> rx = () => ref t.a;
rx() = 5;
Console.WriteLine(t.a); // 5
return rx;
}
You can literally take a pointer to a value type using usafe code
public class Foo
{
public int a;
}
unsafe static class Program
{
static void Main(string[] args)
{
var f=new Foo() { a=1 };
// f.a = 1
fixed(int* ptr=&f.a)
{
*ptr=2;
}
// f.a = 2
}
}
class Test
{
private int a;
/// <summary>
/// points to my variable type interger,
/// where the identifier is named 'a'.
/// </summary>
public int A
{
get { return a; }
set { a = value; }
}
}
Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.
I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.
Properties have a lot of advantages; type safety is one, XML tags another. Start using them!
If one passes an object to a method using the 'Ref' keyword then what is the difference with passing it without the ref keyword?
Because both yield the same result, that the object has been altered when passing control back to the calling object.
Such as this:
class Student
{
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
class Program
{
static Student student = new Student();
static void Main( string[] args )
{
student.Age = 30;
student.Name = "StudentA";
Console.WriteLine("Original Student: {0}, Age: {1}", student.Name, student.Age);
SetStudent(ref student);
Console.WriteLine("Student by Ref {0}, Age{1}", student.Name, student.Age);
AnotherStudent(student);
Console.WriteLine("Just Another Student {0}, Age {1}", student.Name, student.Age);
Console.ReadLine();
}
public static void SetStudent( ref Student student )
{
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
if (studenta.Equals(student))
{
Console.WriteLine("The same object in memory");
}
studenta.Age = 12;
studenta.Name = "StudentX";
}
}
When the student object is passed to AnotherStudent() it gets altered, event thought it is not passed by 'Ref'.
Can someone explain what is happening here?
EDIT
So what is the difference to passing a pointer to an object in C++ in a function?
Tony
Passing by reference allows the method to change the value of the argument passed to the method - so for a reference type, that allows it to change a variable's value to refer to a different object. Here's an example:
using System;
using System.Text;
class Test
{
static void PassByValue(StringBuilder x)
{
x.Append(" - Modified object in method");
x = new StringBuilder("New StringBuilder object");
}
static void PassByReference(ref StringBuilder x)
{
x.Append(" - Modified object in method");
x = new StringBuilder("New StringBuilder object");
}
static void Main()
{
StringBuilder builder = new StringBuilder("Original");
PassByValue(builder);
Console.WriteLine(builder);
builder = new StringBuilder("Original");
PassByReference(ref builder);
Console.WriteLine(builder);
}
}
In both cases, the original StringBuilder has its contents modified, and then the parameter is assigned a new value. In the "pass by value" case, this doesn't change the value of the builder variable in Main. In the "pass by reference" case, the value of builder refers to the new StringBuilder, so the results are:
Original - Modified object in method
New StringBuilder object
In your case, you're not seeing any difference with or without ref because you're not changing the value of the parameter itself - only the data in the object it refers to.
For more information, see my article on parameter passing.
Try reassigning the student object rather than setting properties of it.
public static void SetStudent( ref Student student )
{
student = new Student();
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
studenta = new Student();
studenta.Age = 12;
studenta.Name = "StudentX";
}
Don't think of ref as "passing by reference" because all reference types are passed by reference. Think of it as "reference to this object can be reassigned"
Try changing your two Student methods to:
public static void SetStudent( ref Student student )
{
student = new Student();
student.Age = 16;
student.Name = "StudentY";
}
public static void AnotherStudent( Student studenta )
{
studenta = new Student();
studenta.Age = 12;
studenta.Name = "StudentX";
}
The call to SetStudent will now change your static student variable to reference a new instance because it is passed as a ref. The call to AnotherStudent won't change the reference.
I am limiting the discussion to reference types (everything that is a class, meaning I am not talking about structs or built-in value types). For a full and more detailed discussion you can see this link here.
If you pass reference types without the ref keyword you are passing the reference by value, meaning that a copy of your reference will be made. At this point you can modify the object the ref is pointing to, BUT if you swap in another object (assigning to the ref object you passed in some other object you create) when the function returns the original object that lives outside the function that you passed in is still pointing to the same old reference.
If you pass reference types using the ref keyword instead you can swap in the object you passed in with something else because the reference is not merely being copied - the variable itself is being passed in flesh and bones to the function to do whatever, and you can even make it point to some other address in memory (instantiating another object and assigning it to your ref parameter).
As you point out, in both cases you will be able to modify your object. Basically passing by reference in C# corresponds to passing a simple pointer in C++, while passing without the ref keyword corresponds to passing a constant pointer in C++ (you can make changes but can't make it point to smt else).
Passing a variable by reference and passing a reference type is two different things. You can combine them by passing a reference type varaible by reference.
Passing a variable by reference simply means that the method can change the variable. The method gets access to the variable itself, not just a copy of the value. A variable doesn't have to be a reference type to be passed by reference. The few cases where passing by reference is used is actually mostly with value types.
When passing a reference type by reference, that means that the method gets access to the reference variable, not just a copy of the reference to the object. The method not only have access to the object, but it can also replace the reference in the variable with a reference to a different object.
Passing by reference is rarely needed, and certainly not something that you need to do just because you are passing a reference type as a parameter.
When you pass an object to a method using the ref key word, the called method can update the reference itself, not only the object. That means that in the following code snippet:
object a = new object();
SomeMethod(ref a);
...a may be another object instance after the call than it was before the call. If you pass an object without the ref keyword, the called method can update properties and members of the passed object, but cannot replace the object itself with another instance.
The real difference will become apparent when you do this...
public static void SetStudent( ref Student student )
{
student = new Student { Age = 69, Name="Botox" };
}
...
var a = new Student()
var b = a;
SetStudent(ref a);
object.ReferenceEquals(a, b) // Should be false
These examples illustrates the difference
methodA(ref object a)
{
a = new object();
}
methodB(object a)
{
a = new object();
}
object c = new object();
methodA(ref c); //now c points to an entire new object
methodB(c); // does not change the value of c
Consider the following code (for simplicity, I did not follow any C# coding rules).
public class Professor
{
public string _Name;
public Professor(){}
public Professor(string name)
{
_Name=name;
}
public void Display()
{
Console.WriteLine("Name={0}",_Name);
}
}
public class Example
{
static int Main(string[] args)
{
Professor david = new Professor("David");
Console.WriteLine("\nBefore calling the method ProfessorDetails().. ");
david.Display();
ProfessorDetails(david);
Console.WriteLine("\nAfter calling the method ProfessorDetails()..");
david. Display();
}
static void ProfessorDetails(Professor p)
{
//change in the name here is reflected
p._Name="Flower";
//Why Caller unable to see this assignment
p=new Professor("Jon");
}
}
As expected the output is :
Before calling the method ProfessorDetails()...
Name =David
After calling the method ProfessorDetails()...
Name =Flower
The call p=new Professor("Jon"); in ProfessorDetails(Professor p) is not effective, even though it is reference type. Why should i still need to use the ref keyword to get the desired result?
Everything is passed by value in C#. However, when you pass a reference type, the reference itself is being passed by value, i.e., a copy of the original reference is passed. So, you can change the state of object that the reference copy points to, but if you assign a new value to the reference you are only changing what the copy points to, not the original reference.
When you use the 'ref' keyword it tells the compiler to pass the original reference, not a copy, so you can modify what the reference points to inside of the function. However, the need for this is usually rare and is most often used when you need to return multiple values from a method.
An example:
class Foo
{
int ID { get; set; }
public Foo( int id )
{
ID = id;
}
}
void Main( )
{
Foo f = new Foo( 1 );
Console.WriteLine( f.ID ); // prints "1"
ChangeId( f );
Console.WriteLine( f.ID ); // prints "5"
ChangeRef( f );
Console.WriteLine( f.ID ); // still prints "5", only changed what the copy was pointing to
}
static void ChangeId( Foo f )
{
f.ID = 5;
}
static void ChangeRef( Foo f )
{
f = new Foo( 10 );
}
You've got pass by reference and reference type mixed up.
By changing p, you're not changing the thing that p points at, but where p itself is pointing at, so to speak. And because p has not been declared as ref, the reference (to the reference type) is passed by value, and the change to p is not reflected in the code calling ProfessorDetails. Changes to the instance p was pointing at are reflected (as that's a reference type). Would Professor have been a value type, not even those changes would be visible in the calling code.
There is a difference between passing a reference and a reference to a reference.
When you pass an object (of a reference type) the callee can modify the object data through the underlying pointer, but if the callee modifies the reference, when the function returns, the caller does not read the changed reference off the stack. The callee can not change which object is referenced.
When you pass an object by reference, the callee receives a reference to the reference. The callee has a pointer to the original reference, so can modify the reference (thereby changing what object the reference points to) in addition to modifying the object the reference points to.
The actual value of p is a reference to the same professor instance as david. Any calls you make on that reference are dereferenced as calls to the same instance as would calls made on david be. However, p is a copy of that reference, it's not the same as david value.
Thus, when you do p = new Professor(), you are changing the value of the reference variable to point to a new instance. However, that does not modify the david reference, which still points to the old instance.
If you were to pass p as ref,the value of p would be a reference to the david reference variable. Modifying it would actually modify the david value to point to a new instance.
Regarding on 'passing a reference type' vs 'passing by ref (by using ref key word)', after my research my take away is this:
If you have a reference type object, and keep this object passing from one method to another, the entire time the objects are pointing to a certain location of the memory. If you work on this object for example by changing the property value, this will cause change to the original object. Think as if, in the different methods you were talking about the same person all the time; and in one method you changed the color of the shirt of that person. So that will cause change in the original person object as well.
But, on your path of jumping from one method to another, if you create a new reference for the object (as you are doing by writing 'p=new Professor("Jon")'), you are basically breaking the link between the object in a new method and the original object. Your 'p' now references to another location in the memory. So whatever change you make in this new location of the memory, it will have no effect whatsoever to the original object. However if you want to change the original object address and have the link, you need to use ref key word. BECAREFUL TO USE THE REF KEYWORD, because once in any method, you make the original address in the memory change to a new address (by using ref keyword), all the changes to the original object done in other methods are now gone.
Every reference type is pass by value to a method call. So you can modify the data inside your instance because it is pointing to the same place, but if you want to modify the instance you should use ref
public class Professor
{
public string _Name;
public Professor(){}
public Professor(string name)
{
_Name=name;
}
public void Display()
{
Console.WriteLine("Name={0}",_Name);
}
}
public class Example
{
static int Main(string[] args)
{
Professor david = new Professor("David");
Console.WriteLine("\nBefore calling the method ProfessorDetails().. ");
david.Display();
ProfessorDetails(ref david);
Console.WriteLine("\nAfter calling the method ProfessorDetails()..");
david. Display();
}
static void ProfessorDetails(ref Professor p)
{
//change in the name here is reflected
p._Name="Flower";
//Why Caller unable to see this assignment
p=new Professor("Jon");
}
}
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.