[By default, the CLR assumes that all method parameters are passed by value. When reference type objects are passed, the reference (or pointer) to the object is passed (by value) to the method. This means that the method can modify the object and the caller will see the change. For value type instances, a copy of the instance is passed to the method. This means that the method gets its own private copy of the value type and the instance in the caller isn't affected.
The CLR allows you to pass parameters by reference instead of by value. In C#, you do this by using the out and ref keywords. Both keywords tell the C# compiler to emit metadata indicating that this designated parameter is passed by reference, and the compiler uses this to generate code to pass the address of the parameter rather than the parameter itself.]
I know this is quite misleading, but if you look at the following code sample, then you can better understand the difference:
Object a = new Object(); Object b = new Object();
// This method cannot swap the two objects, // because a and b are passed by value. public void Swap1(Object a, Object b) { Object temp; temp = a; a = b; b = temp; }
// This method does swap the two objects. // because a and b are passed by reference. public void Swap1(ref Object a, ref Object b) { Object temp; temp = a; a = b; b = temp; }
Sheva
Oh dear, it appears we have a real misunderstanding about the way the CLR works. And unfortunately (or rather, Fortunately), C#/VB really do not make it clear how the CLR deals with types at the low level.
I'll try and explain what's going on, but if you didn't come from a C++ background (eg. if you came from VB), you're going to find it quite difficult to follow me. If you care about how the CLR passes objects you'll need to read up on pointers. note: that .NET is designed such that you don't need to care. You can still make decent programs even if you don't fully understand the CLR.
In the CLR, there are these types of objects:
A reference type, unboxed value type, boxed value type, a member of a managed type, an element of a managed array.
In the CLR, every object you declare needs to have allocated for it a block of memory. The reference, boxed value, class-member, and array element ALL have their storage located on the GC heap. Only the unboxed value type has its storage located elsewhere (the stack).
Now the only way to refer to an object on the GC heap is to have a handle to it. You can think of it as a pointer to the GC object. Note that this is the part where you need to have knowledge of C++ and understand pointers. If you don't understand pointers, this is where I'm going to lose you, because I cannot figure out a better way of explaining the CLR.
It's not exactly like a C++ pointer (it needs to be smarter, because GC constantly juggles objects in memory, so you need to have a pointer which understands GC), that's why I call it a "handle". If your object resides in the GC, the only way you can ever refer to it is by using the GC handle.
But if you're referring to the object through pointers GC handles, how comes you're not using pointer like syntax to refer to it What both C# and VB hide from you is the fact that you're referring to the object through the pointer.
Object a = new Object(); // Dim a as New Object
is just syntactic sugar for:
Object *a = new Object();
Note: Managed C++ does not hide the fact that you're referring it through a pointer, but then, that's why we all hate managed C++ .
Now forget about byref and byval for a moment. When you pass an entire Windows Form (ref type) as a parameter to a function, you're passing its GC handle. That's right, you're not passing a 50K size WinForm across (I don't know how big a WinForm is), you're just passing in a 32-bit pointer to that object. If this were an unboxed value like an int, there WOULD be copying across. When you say a parameter is passed, you actually mean a GC handle to the object is passed (unless it's an unboxed value type).
Okay so how does byref and byval fit into all of this When you pass a GC object by value, you are actually passing the GC handle by value. That means although you can fiddle with the underlying object (eg. change its members/properties), you cannot reassign the GC handle to a new one.
Take this code:
private void ChangeName(Form1 yourForm) {
yourForm.Name = "Your Name"; /* works because GC handle points to correct object */ yourForm = new Form1(); // Won't work
}
When you pass a GC object by reference, you are essentially performing a double indirection on the pointer.
ref Form1 yourForm;
is syntactic sugar for:
Form1 **yourForm;
If you don't know pointers you will be well-and-truly lost by now. Now you can reassign the object:
yourForm = new Form1(); // now works: it looks like: *yourForm = new Form1();
I hope that clears things up for you. Now let's take a look at your swap functions.
// This method cannot swap the two objects, // because a and b are passed by value. public void Swap1(Object a, Object b) { Object temp; temp = a; a = b; b = temp; }
Although your comment would be true if a and b were unboxed value types, it is not the correct reason GC types fail. To understand why let's take a look at the function after we remove the syntactic sugar:
public void Swap1(Object *a, Object *b) { Object *temp; temp = a; a = b; b = temp; }
It's your classic pointer dereferencing problem! If you were to perform a swap on a member:
public void SwapTitles(Control a, Control b) { string temp; temp = a.Text; a.Text = b.Text; b.Text = temp; }
This would work! See It's all about the pointers.
Now pretend this was C++ all over again. What is the function to swap two pointers
Now how would we .Net-ify this function Note that Object **a would become ref Object a.
void Swap1(ref Object a, ref Object b) { Object temp; temp = a; a = b; b = temp; }
Wait a moment, this is the Swap2 function you have provided! This is the real reason why Swap2 works but Swap1 doesn't. Pass-by-ref performs double pointer indirection (object **), whereas pass-by-val only applies single indirection (object *).
Even though passing the full class ByVal may seem to be bad from a program design point of view, it doesn't incur as much overhead as you think it does, due to the way the CLR references GC types.
Although the C#/VB languages were designed to abstract away the pointers from you (to the point where you don't even need to know pointers anymore), you still have to have a basic understanding of them and how they work for you to grasp the internal mechanisms on which the CLR is built.
Ok so the framework uses pointers (but smart ones) ... hmm i seem to remember a certain book calling this a delegate .... oh wait that book was also the same data in part of the msdn library ...
I think its safe to say that the average C# programmer doesnt need to know about pointers as such but a knowledge of delegates is kind of key to understanding the language.
So in a roundabout kind of way the average C# programmer wouldnt find C++ that complex ;) (being one myself i can confirm this)
but as stated above this is all a bit overkill just to get 2 forms to pass data between one another !!
maybe a namespace level variable checked as part of the forms message loop would do the job as well
i had a similar problem whilst developing an ftp client ... i had the form and the workings in different classes so i simply declared an event and raised it passing the relevant data from anywhere in my program that required it.
I think thats the easiest way to go and doesnt require a 50 page essay on how the framework passes data around though you guys have kept me amused reading this ;)
Yes its possible to pass values between 2 forms. There are many ways to acheive the same, depending upon your scenerio
Are Form A and Form B part of the the same application
If they are you can write a new Event on Form A and Fire It when the user selects a new data source.
Form B would subscribe to this Event and in the event handling method it would receive the new Data Source and use it to refresh the Grid.
Other way would be if you open Form B from Form A, then in the constructor of Form B you can pass the value of the new data source, although if you ever change the value in form A then you would have to create a new instance of FormB.
Sorry you had to see the resultant flame war thewardy . Hopefully, most readers will just take a look at the marked answer, then they'll skip the subsequent flame war.
As you noted, there are lots of ways to pass data between two forms, (through a helper function, through a public property, through an event that's raised to all subscribers, through passing globals variables, using a mediator class), and some may be more suitable than others.
In your case, an event would be more suitable because the ftp data was received asynchronously. In Mikuno's case, juggling around a mediator class was probably a better choice because he wanted the data read when the user asked it, not when the data changed.
Valentin, this is Windows Forms we're talking about, not ASP.NET Web Forms ! Oh well, it's still useful information to know for other users .
I don't want to labour the point but I think this is quite important. I don't own a copy of that book so I can't look at what you refer to.
Jeffrer Richter wrote:
[By default, the CLR assumes that all method parameters are passed by value. When reference type objects are passed, the reference (or pointer) to the object is passed (by value) to the method. This means that the method can modify the object and the caller will see the change. For value type instances, a copy of the instance is passed to the method. This means that the method gets its own private copy of the value type and the instance in the caller isn't affected.
The CLR allows you to pass parameters by reference instead of by value. In C#, you do this by using the out and ref keywords. Both keywords tell the C# compiler to emit metadata indicating that this designated parameter is passed by reference, and the compiler uses this to generate code to pass the address of the parameter rather than the parameter itself.]
I know this is quite misleading, but if you look at the following code sample, then you can better understand the difference:
Object a = new Object(); Object b = new Object();
// This method cannot swap the two objects, // because a and b are passed by value. public void Swap1(Object a, Object b) { Object temp; temp = a; a = b; b = temp; }
// This method does swap the two objects. // because a and b are passed by reference. public void Swap1(ref Object a, ref Object b) { Object temp; temp = a; a = b; b = temp; }
Actaully it will not cause any real difference in terms of performance. Whilst Mikunos is correct in saying you may as well pass only the data source between the two forms, it makes more sence. It will not be any quicker. Well may be one or two CPU cycles, slower but when a modern (3gig) CPU can do over 3 billion of thoese every second it hardly seems worth quibling over.
The reason for this, is when you pass objects between methods in C# it does whats called, call by reference. It doesn't copy all the memory asosicated with that object and pass the copy to the method it is calling. It passes the method the address where the object is stored in memory. So the form2 is actaully gets the orginal form1 not a copy of it. You can test this by modifying something on form1 from form2. Try changeing the background colour to purble (thats pritty simple and fairly clear if its worked).
The actaul data that is copied is the same size for any object, becuase its only an address to a place in memory. It wouldn't matter if it was a String or a Hashtable with a million strings in it, its just one address.
The only exception to this are the basic bult in data types (int, bool, float and the like) and any Structs which you declar. They are all passed by value. i.e. there contence is coppied and the copy is passed to the method being called. So if form2 changed those the form1 versions would have different values.
I know this might sound a bit pedantic but you will find knowing how data is passed around between methods comes in very usful later.
My idea would be to create a class that controls all the communication with the data. In your first class you can declare the class then pass it by reference to form 2 by modifying the constructor code of the second form. Now both forms can manipulate the data freely. With a little bit of code you can set up events that post back to the forms when data is added, modified or deleted.
I use this when connecting with SQL server databases. In fact I go one step farther by creating a base class that handles all of the actual connection info. (i.e. Server Name, Password, Login stuff) My communication class then inherits the connection class. My forms can then simply reference the communication class.
While this may seem like a lot of work to have 2 forms talk to each other, what it does is set you up with connection and communication classes that can easily be modified for other projects. Going further, I would compile the communication classes into a dll file that all other projects would reference. That way if a change needs to be made, you make it in just the dll file which updates all the other projects you have. (I.E. a server crashes and the new server has a different name)
Thanks for clarifying what you meant by your original post.
You are correct in saying that the reference types pointer is passed by value.
I think we are probably getting in to more detail than is required to explain
why it doesn't matter form a performance point of view the type of object that
is being passed around.
Still as I said earlier this stuff is pretty important to enable the building
of the mental model which every programmer needs to figure out why their code
isn't doing as expected. Using pointers has always been one of the most common
sources of headaches amongst programmers.
I don't want to labour the point but I think this is quite important. I don't own a copy of that book so I can't look at what you refer to.
However I reread the MSDN documentation and its C# language specs. As I though orginally Value Types (the bultin, ints bools, float etc) are passed by value (although that can be overriden using the ref and out keywords) where as reference types (objects, delegates and interfaces) are passed by reference.
According to MSDN
This is because int is a value type. By default, when a value type is passed to a method, a copy is passed instead of the object itself. Because they are copies, any changes made to the parameter have no effect within the calling method. Value types get their name from the fact that a copy of the object is passed instead of the object itself. The value is passed, but not the same object.
This differs from reference types, which are passed by reference. When an object based on a reference type is passed to a method, no copy of the object is made. Instead, a reference to the object being used as a method argument is made and passed. Changes made through this reference will therefore be reflected in the calling method. A reference type is created with the class keyword, like this:
You can read this whole article in the Visual Studio help system by entering in this address ms-help://MS.VSExpressCC.v80/MS.NETFramework.v20.en/dv_csref/html/cc738f07-e8cd-4683-9585-9f40c0667c37.htm
Comunication between two forms
Rock Climber
Oh dear, it appears we have a real misunderstanding about the way the CLR works. And unfortunately (or rather, Fortunately), C#/VB really do not make it clear how the CLR deals with types at the low level.
I'll try and explain what's going on, but if you didn't come from a C++ background (eg. if you came from VB), you're going to find it quite difficult to follow me. If you care about how the CLR passes objects you'll need to read up on pointers. note: that .NET is designed such that you don't need to care. You can still make decent programs even if you don't fully understand the CLR.
In the CLR, there are these types of objects:
A reference type,
unboxed value type,
boxed value type,
a member of a managed type,
an element of a managed array.
In the CLR, every object you declare needs to have allocated for it a block of memory. The reference, boxed value, class-member, and array element ALL have their storage located on the GC heap. Only the unboxed value type has its storage located elsewhere (the stack).
Now the only way to refer to an object on the GC heap is to have a handle to it. You can think of it as a pointer to the GC object. Note that this is the part where you need to have knowledge of C++ and understand pointers. If you don't understand pointers, this is where I'm going to lose you, because I cannot figure out a better way of explaining the CLR.
It's not exactly like a C++ pointer (it needs to be smarter, because GC constantly juggles objects in memory, so you need to have a pointer which understands GC), that's why I call it a "handle". If your object resides in the GC, the only way you can ever refer to it is by using the GC handle.
But if you're referring to the object through
pointersGC handles, how comes you're not using pointer like syntax to refer to it What both C# and VB hide from you is the fact that you're referring to the object through the pointer.Object a = new Object(); // Dim a as New Object
is just syntactic sugar for:
Object *a = new Object();
Note: Managed C++ does not hide the fact that you're referring it through a pointer, but then, that's why we all hate managed C++
.
Now forget about byref and byval for a moment. When you pass an entire Windows Form (ref type) as a parameter to a function, you're passing its GC handle. That's right, you're not passing a 50K size WinForm across (I don't know how big a WinForm is), you're just passing in a 32-bit pointer to that object. If this were an unboxed value like an int, there WOULD be copying across. When you say a parameter is passed, you actually mean a GC handle to the object is passed (unless it's an unboxed value type).
Okay so how does byref and byval fit into all of this When you pass a GC object by value, you are actually passing the GC handle by value. That means although you can fiddle with the underlying object (eg. change its members/properties), you cannot reassign the GC handle to a new one.
Take this code:
private void ChangeName(Form1 yourForm)
{
yourForm.Name = "Your Name"; /* works because GC handle points to correct object */
yourForm = new Form1(); // Won't work
}
When you pass a GC object by reference, you are essentially performing a double indirection on the pointer.
ref Form1 yourForm;
is syntactic sugar for:
Form1 **yourForm;
If you don't know pointers you will be well-and-truly lost by now. Now you can reassign the object:
yourForm = new Form1(); // now works: it looks like:
*yourForm = new Form1();
I hope that clears things up for you. Now let's take a look at your swap functions.
// This method cannot swap the two objects,
// because a and b are passed by value.
public void Swap1(Object a, Object b)
{
Object temp;
temp = a;
a = b;
b = temp;
}
Although your comment would be true if a and b were unboxed value types, it is not the correct reason GC types fail. To understand why let's take a look at the function after we remove the syntactic sugar:
public void Swap1(Object *a, Object *b)
{
Object *temp;
temp = a;
a = b;
b = temp;
}
It's your classic pointer dereferencing problem! If you were to perform a swap on a member:
public void SwapTitles(Control a, Control b)
{
string temp;
temp = a.Text;
a.Text = b.Text;
b.Text = temp;
}
This would work! See It's all about the pointers.
Now pretend this was C++ all over again. What is the function to swap two pointers
void Swap1(Object **a, Object **b)
{
Object *temp;
temp = *a;
*a = *b;
*b = temp;
}
Now how would we .Net-ify this function Note that Object **a would become ref Object a.
void Swap1(ref Object a, ref Object b)
{
Object temp;
temp = a;
a = b;
b = temp;
}
Wait a moment, this is the Swap2 function you have provided! This is the real reason why Swap2 works but Swap1 doesn't. Pass-by-ref performs double pointer indirection (object **), whereas pass-by-val only applies single indirection (object *).
Even though passing the full class ByVal may seem to be bad from a program design point of view, it doesn't incur as much overhead as you think it does, due to the way the CLR references GC types.
Although the C#/VB languages were designed to abstract away the pointers from you (to the point where you don't even need to know pointers anymore), you still have to have a basic understanding of them and how they work for you to grasp the internal mechanisms on which the CLR is built.
Petru Moldovan
FORM1
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace CallForm
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
public System.Windows.Forms.DataGrid dataGrid1;
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dataGrid1 = new System.Windows.Forms.DataGrid();
this.button1 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).BeginInit();
this.SuspendLayout();
//
// dataGrid1
//
this.dataGrid1.DataMember = "";
this.dataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dataGrid1.Location = new System.Drawing.Point(27, 51);
this.dataGrid1.Name = "dataGrid1";
this.dataGrid1.Size = new System.Drawing.Size(341, 167);
this.dataGrid1.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(264, 7);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(104, 33);
this.button1.TabIndex = 2;
this.button1.Text = "button1";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(396, 234);
this.Controls.Add(this.button1);
this.Controls.Add(this.dataGrid1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGrid1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
Form2 f=new Form2(this);
f.Show();
}
private void Form1_Load(object sender, System.EventArgs e)
{
}
}
}
FORM2
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CallForm
{
/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button button1;
private Form older;
public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
public Form2(Form f)
{
this.older=f;
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(175, 75);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(76, 35);
this.button1.TabIndex = 0;
this.button1.Text = "Aggiorna DataGrid";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(423, 233);
this.Controls.Add(this.button1);
this.Name = "Form2";
this.Text = "Form2";
this.Load += new System.EventHandler(this.Form2_Load);
this.ResumeLayout(false);
}
#endregion
private void Form2_Load(object sender, System.EventArgs e)
{
}
private void button1_Click(object sender, System.EventArgs e)
{
string[] arr={"david","lorenzo","turillo"};
Form1 p=(Form1)this.older;
p.dataGrid1.DataSource=arr;
}
}
}
killerless
Hello Mikunos
what ever the code written in right but its very costly in case of Preformance ..
instead of passing the entire form u cna pass the Data set alone.
Chris Forrester
You can send all kind of data between Forms using the Session varialbe.
For instance:
The FormB has the DataGrid dg1, whose data source is the DataSet ds1.
The FormA has the DataGrid dg2, whose data source is the DataSet ds2.
The code whitin FormB:
Session ["DataSet"] = ds1;
Somewhere you make a redirect to FormA, such as:
Response.Redirect ("FormA.aspx");
The code whitin FormA:
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
if (Session ["DataSet"] != null)
{
ds2 = (DataSet)Session ["DataSet"];
dg2.DataBind ();
}
}
}
Have a fun!< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Valentin
Do not hesitate to contact me!
www.wwv-it.eu
Harrelson
Ok so the framework uses pointers (but smart ones) ... hmm i seem to remember a certain book calling this a delegate .... oh wait that book was also the same data in part of the msdn library ...
I think its safe to say that the average C# programmer doesnt need to know about pointers as such but a knowledge of delegates is kind of key to understanding the language.
So in a roundabout kind of way the average C# programmer wouldnt find C++ that complex ;) (being one myself i can confirm this)
but as stated above this is all a bit overkill just to get 2 forms to pass data between one another !!
maybe a namespace level variable checked as part of the forms message loop would do the job as well
i had a similar problem whilst developing an ftp client ... i had the form and the workings in different classes so i simply declared an event and raised it passing the relevant data from anywhere in my program that required it.
I think thats the easiest way to go and doesnt require a 50 page essay on how the framework passes data around though you guys have kept me amused reading this ;)
BNavas
Are Form A and Form B part of the the same application
If they are you can write a new Event on Form A and Fire It when the user selects a new data source.
Form B would subscribe to this Event and in the event handling method it would receive the new Data Source and use it to refresh the Grid.
Other way would be if you open Form B from Form A, then in the constructor of Form B you can pass the value of the new data source, although if you ever change the value in form A then you would have to create a new instance of FormB.
I think the first method would be the best.
M D L
The following code may help u.
Form1 Code
--------------------
public
static DataSet Ds = new DataSet(); private void Form1_Load(object sender, System.EventArgs e){
DataTable dt =
new DataTable();dt.Columns.Add("Name",
typeof(System.String));dt.Columns.Add("Address",
typeof(System.String));DataRow dr = dt.NewRow();
dr["Name"] = "Nirmalya";
dr["Address"] = "Kolkata";
dt.Rows.Add(dr);
Ds.Tables.Add(dt);
}
Form2 Code
-------------------
if
(Form1.Ds.Tables.Count > 0){
foreach(DataRow dr in Form1.Ds.Tables[0].Rows){
MessageBox.Show(dr["Name"].ToString());
MessageBox.Show(dr["Address"].ToString());
}
}
This is how you can use DataSet of Form1 in Form2
Josh_G
Actually, in C#, you pass objects between methods by value, not matter whether those objects are of value type or reference type, please refer to Jeffrey Richter's Applied Microsoft .NET Framework Programming for more information.
Sheva
urgrund
Sorry you had to see the resultant flame war thewardy
. Hopefully, most readers will just take a look at the marked answer, then they'll skip the subsequent flame war.
As you noted, there are lots of ways to pass data between two forms, (through a helper function, through a public property, through an event that's raised to all subscribers, through passing globals variables, using a mediator class), and some may be more suitable than others.
In your case, an event would be more suitable because the ftp data was received asynchronously. In Mikuno's case, juggling around a mediator class was probably a better choice because he wanted the data read when the user asked it, not when the data changed.
Valentin, this is Windows Forms we're talking about, not ASP.NET Web Forms
! Oh well, it's still useful information to know for other users
.
clint440
Jeffrer Richter wrote:
[By default, the CLR assumes that all method parameters are passed by value. When reference type objects are passed, the reference (or pointer) to the object is passed (by value) to the method. This means that the method can modify the object and the caller will see the change. For value type instances, a copy of the instance is passed to the method. This means that the method gets its own private copy of the value type and the instance in the caller isn't affected.
The CLR allows you to pass parameters by reference instead of by value. In C#, you do this by using the out and ref keywords. Both keywords tell the C# compiler to emit metadata indicating that this designated parameter is passed by reference, and the compiler uses this to generate code to pass the address of the parameter rather than the parameter itself.]
I know this is quite misleading, but if you look at the following code sample, then you can better understand the difference:
Object a = new Object();
Object b = new Object();
// This method cannot swap the two objects,
// because a and b are passed by value.
public void Swap1(Object a, Object b)
{
Object temp;
temp = a;
a = b;
b = temp;
}
// This method does swap the two objects.
// because a and b are passed by reference.
public void Swap1(ref Object a, ref Object b)
{
Object temp;
temp = a;
a = b;
b = temp;
}
Sheva
Dr Cube
The reason for this, is when you pass objects between methods in C# it does whats called, call by reference. It doesn't copy all the memory asosicated with that object and pass the copy to the method it is calling. It passes the method the address where the object is stored in memory. So the form2 is actaully gets the orginal form1 not a copy of it. You can test this by modifying something on form1 from form2. Try changeing the background colour to purble (thats pritty simple and fairly clear if its worked).
The actaul data that is copied is the same size for any object, becuase its only an address to a place in memory. It wouldn't matter if it was a String or a Hashtable with a million strings in it, its just one address.
The only exception to this are the basic bult in data types (int, bool, float and the like) and any Structs which you declar. They are all passed by value. i.e. there contence is coppied and the copy is passed to the method being called. So if form2 changed those the form1 versions would have different values.
I know this might sound a bit pedantic but you will find knowing how data is passed around between methods comes in very usful later.
Charlie
yinmin
My idea would be to create a class that controls all the communication with the data. In your first class you can declare the class then pass it by reference to form 2 by modifying the constructor code of the second form. Now both forms can manipulate the data freely. With a little bit of code you can set up events that post back to the forms when data is added, modified or deleted.
I use this when connecting with SQL server databases. In fact I go one step farther by creating a base class that handles all of the actual connection info. (i.e. Server Name, Password, Login stuff) My communication class then inherits the connection class. My forms can then simply reference the communication class.
While this may seem like a lot of work to have 2 forms talk to each other, what it does is set you up with connection and communication classes that can easily be modified for other projects. Going further, I would compile the communication classes into a dll file that all other projects would reference. That way if a change needs to be made, you make it in just the dll file which updates all the other projects you have. (I.E. a server crashes and the new server has a different name)
AlanSweet
Thanks for clarifying what you meant by your original post. You are correct in saying that the reference types pointer is passed by value. I think we are probably getting in to more detail than is required to explain why it doesn't matter form a performance point of view the type of object that is being passed around.
Still as I said earlier this stuff is pretty important to enable the building of the mental model which every programmer needs to figure out why their code isn't doing as expected. Using pointers has always been one of the most common sources of headaches amongst programmers.
Charlie
Paul.Prasanta
However I reread the MSDN documentation and its C# language specs. As I though orginally Value Types (the bultin, ints bools, float etc) are passed by value (although that can be overriden using the ref and out keywords) where as reference types (objects, delegates and interfaces) are passed by reference.
According to MSDN
This is because int is a value type. By default, when a value type is passed to a method, a copy is passed instead of the object itself. Because they are copies, any changes made to the parameter have no effect within the calling method. Value types get their name from the fact that a copy of the object is passed instead of the object itself. The value is passed, but not the same object.
This differs from reference types, which are passed by reference. When an object based on a reference type is passed to a method, no copy of the object is made. Instead, a reference to the object being used as a method argument is made and passed. Changes made through this reference will therefore be reflected in the calling method. A reference type is created with the class keyword, like this:
You can read this whole article in the Visual Studio help system by entering in this address ms-help://MS.VSExpressCC.v80/MS.NETFramework.v20.en/dv_csref/html/cc738f07-e8cd-4683-9585-9f40c0667c37.htm