You don't need to use pointers - in C# there are two kinds of types: (1) value types (structs), which are passed around by value, and (2) reference types (classes), instances of which are really references to objects (garbage collected pointers of sort), and are thus effectively passed by reference. Basically, class instances behave akin to C++ pointers, except you don't have to delete them manually, and you're not allowed to do pointer arithmetic.
So, you only need to declare it this way: Node next;
// or
Node next = null;
And then when you add a node, you simply write: next = node;
It essentially makes next point to a different object. You continue to use the member access operator (".") as usual.
BTW, if it's relevant, the .NET library comes with a LinkedList<T> generic class (a doubly linked list).
Last edited by TheGreatCthulhu; October 11th, 2012 at 06:41 AM.
CSharp uses the unsafe keyword as you know to allow you to use pointers. Unsafe code is very C-Like. I believe the closest you can get to a pointer to a user defined class is a pointer to a struct. This is done to allow inter-op with Win32 and other external C/C++ libraries and memory mapped devices. Other than that, you can make pointers to the built in types, that are also classes.
If you have an interop scenario, you might need to use pointers and "unsafe" blocks, but, IMO, if you're rewriting code to C#, then, with reference types available, there's really no need for pointers.
Sorry, just a question: when you say "ref"-s, did you use ref method parameters or did you mean reference types? If you used ref parameters, there's no need for that either.
If that's the case, I'll explain about the ref later.
public static void Test(int val)
{
val = -val;
}
public static void Test(string val)
{
val = val.ToLower(); // ToLower() returns a new string, all in lowercase
}
public static void Test(Element val)
{
// mutate
val.Value = "The Old New Thing";
// replace
val = new Element();
val.Value = "New!";
}
What will the value of the original object be when the methods return? To answer that question, you must understand the distinction which C# makes between value types (structs) and reference types (classes). All the fundamental types (byte, int, long, float, double, bool...), except for string, are value types. They are passed around by value by default. String type is a reference type, but is specific in that it's, by design, immutable. That is, when you assign a new string to a variable, it's not the contents of the string objects that changes, but the whole object itself gets replaced. (This enables the language to share same string literals among string variables.) Now, for the code above, all of the variables are local copies, so replacing them will not have any effect on the original. So, the integer will not change, the original string will not be replaced, and the Element object (a reference type) will not be replaced, but it will be mutated (changed internally), and it's Value property will be "The Old New Thing".
It's like when you pass a pointer to an object in C++: a local copy of the pointer is made, but it still points to the same object, so you can modify that object.
Code:
Originals:
n: 5
s: STRING!
e: OLD
No ref keyword:
n: 5
s: STRING!
e: The Old New Thing
Now, in C#, the ref keyword is a part of the signature, so you can overload all those methods, like this:
Code:
public static void Test(ref int val)
{
val = -val;
}
public static void Test(ref string val)
{
val = val.ToLower();
}
public static void Test(ref Element val)
{
// mutate
val.Value = "The Old New Thing";
// replace
val = new Element();
val.Value = "New!";
}
What happens now?
For value types, it's straightforward - the ref keyword forces them to be passed by reference. For reference types, the reference itself is passed by reference - analogous to a C++ pointer being passed by reference. This means that you can now make it point to an entirely different object. So, after each of the methods returns, the original integer will be changed, the original string variable will point to a new string, and the original element variable will point to a new object, with the Value property set to "New!".
Code:
Originals
n: 5
s: STRING
e: OLD
Using ref
n: -5
s: string
e: New!
You can try calling these methods in a console application, in the Main() method, and see for yourself. Something like this:
Code:
int n = 5;
string s = "STRING!";
Element e = new Element(); // This is just some class (the one I used in your other thread, the linked list example)
e.Value = "OLD"; // all it does is it stores a string value
Console.WriteLine("Originals:");
PrintValues(n, s, e);
Test(n);
Test(s);
Test(e);
Console.WriteLine("No ref keyword:");
PrintValues(n, s, e);
Test(ref n);
Test(ref s);
Test(ref e);
Console.WriteLine("Using ref keyword:");
PrintValues(n, s, e);
P.S. In the IDE, you can discover if a type is a value type or a reference type by hovering a mouse over a type name and looking if it says struct or class. You can also rely on the MSDN documentation.
Last edited by TheGreatCthulhu; October 12th, 2012 at 02:20 PM.
I just noticed that I didn't answer your question directly, so:
Originally Posted by dazibao
I use it to pass by reference. Can I overpass this too??
for ex:
void Change(ref string xy) { xy="hi";}
string x = "hello"
Change(ref x);
//now x= "hi"';
If you want to do it that way, then you must use the ref keyword, because, as I said, string is an immutable type. (There's also a mutable variant, called StringBuilder.) So, xy="hi" does not modify the original string object, it actually assigns a completely different object to the variable (read the post above for more detail). But if you had a regular, mutable object, such is, say, a Button (Win Forms), then this would work:
Code:
void Change(Button btn) { btn.Text = "Hi"; }
Button b = new Button();
b.Text = "Hello";
Change(b); // a reference type behaves a lot like a pointer, but it's garbage collected
//now b.Text == "Hi"';
This next variation wouldn't work without the ref keyword, though:
Code:
void Change(Button btn)
{
btn = new Button(); // Trying to replace the original object, which is what actually happens with strings
btn.Text = "Hi"; // At this point, btn has nothing to do with the btn that was originally passed here
}
Button b = new Button();
b.Text = "Hello";
Change(b);
//now, it's still: b.Text == "Hello"';
If you have a linked list of elements which contain strings, then you can write an Add() or an Insert(), or a Replace() method without using the ref keyword:
Code:
public void Add(string item)
{ /* ...assign item to an internal element... */ }
The string, being a class, is passed as a reference to the original string object (analogous to a C++ pointer). In the case of the replace method, you can simply set the internal member variable using "someVar = item", and it will point to the original object.
Basically, if it's a class, it behaves a lot like a pointer, if it's a struct, is just passed by value.
Last edited by TheGreatCthulhu; October 12th, 2012 at 03:02 PM.
It doesnt change the string back to the caller. I guess the new value can only be assigned in that method that takes the ref parameter, but this can't be done as you see.
There are 2 major problems with that.
First, this doesn't work because although you assign str to the sRef variable, you are simply making it point to the same object. sRef is still a different variable. What's passed by reference to the function is str, so only assigning something to str will affect the original variable.
Now, when you tried assigning str = sRef in the constructor, you did change to what the original variable points to, and if it was an object of a mutable type, the code in bOK_Click would affect it. Note that sRef and str are still different variables pointing to the same object, but this can change.
And, as string is immutable, it does change in the click event handler, which is pretty much is equivalent to:
Code:
private void bOK_Click(object sender, EventArgs e)
{
sRef = new String("Whatever"); // sRef and str no longer point to the same object!
}
The second problem is that, even if the code worked, it breaks encapsulation - it tries to modify internal data of a different class, and that is not a good thing.
The proper way to do it is to define a suitable public interface (by providing a set of public methods and/or properties) on the SaveQueryAs class, which can be used to retrieve the string object (or any other data).
For example, take OpenFileDialog: once the user selects a file and closes the dialog, the form that has shown the dialog window can retrieve the path via the FileName property of the OpenFileDialog class.
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
System.IO.StreamReader sr = new
System.IO.StreamReader(openFileDialog1.FileName);
MessageBox.Show(sr.ReadToEnd());
sr.Close();
}
So, similarly, define a public property on the SaveQueryAs class; you can name it UserInput, or some other name you think is adequate, and then simply set the value of that property inside the bOK_Click handler.
Then, when the SaveQueryAs dialog is closed, and the control flow returns to the bSave_Click method in Form1, you can simply do: str = save.UserInput;
Last edited by TheGreatCthulhu; November 14th, 2012 at 08:03 AM.
Bookmarks