I have a program like this
class Program
{
static void Main(string[] args)
{
test objtest = new test();
objtest.Name = "vikas";
Test(objtest);
//objtest = null; when I uncomment this line it shows me exception
Console.WriteLine(objtest.Name);
Console.ReadLine();
}
private static void Test(test objtest)
{
objtest.Name = "chetan";
objtest = null;
}
}
class test
{
private string _Name = string.Empty;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
}
Output:
chetan
Second program:
class Program
{
static void Main(string[] args)
{
test objtest = new test();
objtest.Name = "vikas";
Test(objtest);
objtest = null;
try
{
Console.WriteLine(objtest.Name);
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException + " " + ex.Message);
}
Console.ReadLine();
}
private static void Test(test objtest)
{
objtest.Name = "chetan";
objtest = null;
}
}
class test
{
private string _Name = string.Empty;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
}
Output:
Object reference not to set an instance of object
Why?
When I set objtest = null; in Test it shows me the value, but when I set null in same it shows me error.
Added after #kmatyaszek post:
In first program
static void Main(string[] args)
{
test objtest = new test();
objtest.Name = "vikas"; // **I am assigning this value**
Test(objtest);
//objtest = null; when I uncomment this line it shows me exception
Console.WriteLine(objtest.Name);
Console.ReadLine();
}
private static void Test(test objtest)
{
objtest.Name = "chetan";
objtest = null;
}
Why it is displaying "chetan" not "vikas"??
Classic confusion caused by reference type that is being passed by value.
I will give a rather short and simple answer here; those interested to learn more and in depth are more than welcome to read Jon Skeet article on Parameter passing in C# and similar article with diagrams, by Lee Richardson.
Reference type, in short, is any type that is not primitive or struct. Any custom defined class is hence a reference type.
When instance of such class is passed to a function, what actually happens is that a pointer to this instance is passed. More accurately, a copy of the pointer is being passed since by default parameters are passed by value.
When you have this line:
test objtest = new test();
New instance of the class test is being created and assigned address in the memory. Every time you refer to the variable objtest, that address will be used for example:
objtest.Name = "vikas";
The runtime engine will go the address assigned when the instance was created, look for the place reserved for the property Name and change the contents there to "vikas". The change is immediate and permanent for this instance.
When you have such function signature:
private static void Test(test objtest)
The actual parameter that is passed "behind the scenes" is the address of the instance in the memory. Whenever you refer to the parameter objtest inside the function, the runtime engine will go to the address passed as the actual parameter. So having this line inside the function:
objtest.Name = "chetan";
Is exactly the same as having it outside the function: it will look for the place reserved for the property Name in the memory address passed, and change the contents there to "chetan". Yet again, this change is immediate and permanent for that instance. For this thing (changing properties) it doesn't matter if you're using ref or not, as you are dealing with reference type.
However, being passed by value (e.g. without ref keyword) means that the memory address is being copied and the function only get the copy, very much like passing integer. Any change to the copy will not affect the original value. Thus, when you have this line inside the function:
objtest = null;
You change the copy to point on nothing, however the variable outside the function still point to the same address and won't be null.
If you have such function signature:
private static void Test(ref test objtest)
Then it means the address itself is passed by reference, hence changing the variable holding the address will cause it to be changed outside the function as well.
This pretty much sums it up, I don't bring anything new here just clarifying things with what I deem more simple explanation.
You have problem here with passing parameter to function.
Default parameters are passed by value.
The attempt to reassign the parameter to a different memory location only works inside the method Test and does not affect the original variable objtest in Main method.
So when you add ref to parameter in Test function in two cases behaviour will be the same, because all of the changes that take place inside the method Test affect the original object objtest in Main method.
First example from your question with ref parameter:
class Program
{
static void Main(string[] args)
{
test objtest = new test();
objtest.Name = "vikas";
Test(ref objtest);
//objtest = null; when I uncomment this line it shows me exception
Console.WriteLine(objtest.Name);
Console.ReadLine();
}
private static void Test(ref test objtest)
{
objtest.Name = "chetan";
objtest = null;
}
}
class test
{
private string _Name = string.Empty;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
}
In the second example first you set null to original object and after that you want read property Name, so you will get NullReferenceException.
Well, you're using an object with a value of null, which causes the exception. null for reference types means "points to zero". When you're trying to access the value stored at address zero, you get a NullReferenceException.
You're setting objtest to null before you access the Name property, so you're trying to access the Name property of the object stored at address zero, which makes no sense.
Related
First , I'm a C++ dev and new to C# , Sorry for this simple question.
I'm creating a wrapper for my native library.
I want to pass a value in a class and edit it from some other function in class , like pointers in C++ , I found out it can be done with unsafe mode but I need to do it without unsafe and I'm sure it's possible.
Here's my code :
Main Console
namespace ConsoleApp2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string DATA_VALUE = "Not Set Yet";
new Data_Picker_Form(DATA_VALUE).ShowDialog();
Console.WriteLine("Value is {0}", DATA_VALUE);
Console.ReadKey();
}
}
}
Form Code
using System;
using System.Windows.Forms;
namespace ConsoleApp2
{
public partial class Data_Picker_Form : Form
{
object data_in_obj;
public Data_Picker_Form(string data_in)
{
InitializeComponent();
data_in_obj = data_in;
}
private void button1_Click(object sender, EventArgs e)
{
string data_in_new = data_in_obj as string;
data_in_new = "OUTPUT_VALUE";
this.Close();
}
}
}
it's not working unfortunately , so I need to pass my string , int and etc. value to a new form , in initializing form creates a instance [like pointer] to original string and it can accessible from other functions ins class like button click.
thanks.
You already have a reference (sort of like a pointer), and that is your problem (well, half of it anyways).
string data_in_new = data_in_obj as string;
Says to create a variable that holds a string reference (as strings are immutable reference types) and copy the reference data_in_obj currently has to it. When you then reassign data_in_new it of course doesn't affect any other variable (just like it wouldn't in C++).
Because strings are immutable, there is no way for that code to affect other things that point to that string (passing by reference aside, but this is about variables/members). You need to store it in a simple struct or class so that everyone is pointing at an object that holds the current string reference, and can be updated.
Same idea with your int, it is actually a value type so any copy will copy the actual value, you can't change a different variable through it. You need a wrapper class so that each user is pointing at the same object.
What about setting up a simple get and set function since you are already Initializing your Form?
In Your Form:
private string data_in_new = "";
public Data_Picker_Form(string DATA_VALUE)
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Data_in_new = "OUTPUT_VALUE";
Close();
}
public string Data_in_new
{
get
{
return data_in_new;
}
set
{
data_in_new = value;
}
}
And in your Console:
class Program
{
static void Main(string[] args)
{
string DATA_VALUE = "Not Set Yet";
Data_Picker_Form D_P_T = new Data_Picker_Form(DATA_VALUE);
D_P_T.ShowDialog();
DATA_VALUE = D_P_T.Data_in_new;
Console.WriteLine("Value is {0}", DATA_VALUE);
Console.ReadKey();
}
}
This Way you can access you value at any desired point in the project.
I'm unable to assign a value to a property inside a struct without using a new keyword to initialize the struct. If I try to assign a value to the property I get the below error. But I can assign a value to the public variable or call a method inside the struct without a new keyword. I'm trying to find a reason for this behavior. Please help.
Error: Use of unassigned local variable 'pd2'
struct P
{
public int i;
public int j;
public string e;
public string Name { get; set; }
public void Showi()
{
Console.WriteLine(string.Format("Display i:{0}",this.i));
}
}
static void Main(string[] args)
{
P pd2;
pd2.i = 1;
pd2.j = 1;
pd2.e = "test";
pd2.Name = "abc"; //This is a property, shows error here
}
call a method inside the struct without a new keyword
You can only call a method on the struct if you have ensured that every field is initialized (which results in the entire struct being initialized). If you haven't fully initialized very field, then you can't perform any other operations on it, as the error message you're getting is telling you. You'll need to initialize all of the fields before you're able to use that property setter, such as by calling the default constructor.
Consider following code, I am trying to implement custom link list.
Expected Output : Start-->123-->11-->NULL
Actual Output : Start-->11-->NULL
class MyLinkList
{
public object data { get; set; }
public MyLinkList Next { get; set; }
}
public static void PrintLinkList(MyLinkList start)
{
Console.Write("Start-->");
while (start != null)
{
Console.Write(start.data + "-->");
start = start.Next;
}
Console.Write("NULL");
}
public static void AddNodeStart( MyLinkList start, object data)
{
MyLinkList newNode = new MyLinkList();
newNode.data = data;
newNode.Next = start;
start = newNode;
}
public static void Main()
{
MyLinkList n = new MyLinkList() { data = 11, Next = null };
AddNodeStart( n,123);
PrintLinkList(n);
Console.ReadLine();
}
The problem is even though node is added to the list in the AddToStart function, its value is not persisted when control come back to main function.
Object is passed by reference then why its value is not getting persisted. if I use 'ref' word then I get the expected result.
Atul sureka
Add ref to your method declaration like so:
public static void AddNodeStart(ref MyLinkList start, object data)
then call it
AddNodeStart(ref n,123);
and it should work.
If you don't, then start is just a variable inside AddNodeStart method - assigning values to it will not change reference stored in n.
That said it is rather a bad taste to do this. Instead consider returning the new node from your add method.
public static MyLinkList AddNodeStart(MyLinkList start, object data)
{
MyLinkList newNode = new MyLinkList();
newNode.data = data;
newNode.Next = start;
return newNode;
}
then call it this way:
n = AddNodeStart(n,123);
Because the reference in C# (also in Java) is passed by value. The actually reference used in the method is the copy of the reference value passed in. (The object being referred is not copied)
Another example is you can't swap 2 objects by passing the references into a method. Since all references are passed by value, what you actually swap is the values of the copied references.
Go the answer from Why use the 'ref' keyword when passing an object?.
Value is not getting persisted because I am creating a new object in AddNodeStart. If I modify the existing object in the function then the changes would be persisted.
Take for example a simple method:
public string GetDisplayName(string username, IUserService UserService)
{
var user = UserService.GetUserByUsername(username);
return string.Format("{0} {1} {2} ({3})", user.Title, user.FirstName, user.LastName, username);
}
So UserService is a class, and by definition in C#, a class is a reference type.
If I were to do the following:
public string GetDisplayName(string username, ref IUserService UserService)
{
var user = UserService.GetUserByUsername(username);
return string.Format("{0} {1} {2} ({3})", user.Title, user.FirstName, user.LastName, username);
}
What are the main differences here?
In your specific example, there is no difference because you are not assigning anything to the parameter UserService.
However, if you were to assign a new instance to the UserService parameter, that would change the object referenced by caller of that method.
Here's a sample program to demonstrate the difference:
using System;
namespace Demo
{
class Demo
{
public int Value;
public Demo(int value)
{
Value = value;
}
}
class Program
{
private static void test1(Demo demo)
{
demo = new Demo(42);
}
private static void test2(ref Demo demo)
{
demo = new Demo(42);
}
private static void Main()
{
Demo demo1 = new Demo(0);
Demo demo2 = demo1; // demo2 references demo1.
// Calling test1() will NOT change the object referenced by demo1:
test1(demo1);
Console.WriteLine(demo1.Value); // Prints 0
demo2.Value = 1;
Console.WriteLine(demo1.Value); // Prints 1, indicating that changing demo2 also changed demo1
// Calling test2() will cause demo1 to reference a DIFFERENT instance of class Demo:
test2(ref demo1);
Console.WriteLine(demo1.Value); // Prints 42, indicating that demo1 was changed.
demo2.Value = 1;
Console.WriteLine(demo1.Value); // Prints 42, indicating that changing demo2 no longer changes demo1
}
}
}
The differences are:
The method with the ref parameter needs to be called with a variable for that parameter. If you for example would use new CompanyUserService() to create the user service for the call, you would need to put that in a variable and use the variable in the call instead of just passing on the newly created reference.
Inside the method with the ref parameter, the value of the variable used in the call can be changed. In the other method the parameter is a copy of the value, so changing the value of the parameter variable inside the method will not affect anything outside the method.
Parameters with the ref keyword are sent as pointers to the variable containing the value instead of the value itself, so whenever you use the parameter in the method there is another step of redirection.
(The last point is not dictated by the specifications, but that is how the actual implementations handle the ref parameters. The specifications only state how the parameters should work, not how it should be implemented.)
Could you please explain the following behavior of C# Class. I expect the classResult as "Class Lijo"; but actual value is “Changed”.
We’re making a copy of the reference. Though the copy is pointing to the same address, the method receiving the argument cannot change original.
Still why the value gets changed ?
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
String nameString = "string Lijo";
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(nameString, p);
string classResult = p.Name;
Response.Write(nameString + "....." + classResult);
}
}
public class Utilityclass
{
public static void TestMethod(String nameString, Person k)
{
nameString = "Changed";
k.Name = "Changed";
}
}
public class Person
{
public string Name
{
get; set;
}
}
Update: When I pass a String, it does not get actually changed.
The briefest answer is: read my article on parameter passing which goes into this in a fair amount of detail.
The slightly longer answer is to compare these two methods, both of which use value parameters:
public void ChangeMe(string x)
{
x = "changed";
}
public void ChangeMe(Person x)
{
x.Name = "changed";
}
In the first case, you are changing the value of the parameter. That is completely isolated from the original argument. You can't change the content of the string itself, because strings are immutable.
In the second case, you are changing the contents of the object which the parameter's value refers to. That's not changing the value of the parameter itself - it will be the same reference. To give a real world example, if someone delivers something to your house that changes the contents of your house, but it doesn't change your house's address.
If you changed the second method to this:
public void ChangeMe(Person x)
{
x = new Person("Fred");
}
then the caller wouldn't see any change. This is closer to what you're doing with a string - you're making the parameter refer to a different object, rather than changing the contents of the existing object.
Now, when you use a ref parameter, the variable used by the caller as the argument is "aliased" with the parameter - so if you change the value of the parameter, that changes the value of the argument as well. So if we change the last method like this:
public void ChangeMe(ref Person x)
{
x = new Person("Fred");
}
then:
Person y = new Person("Eric");
ChangeMe(ref y);
Console.WriteLine(y.Name);
this will print out "Fred".
The key concept to understand is that the value of a variable is never an object - it's either a value type value or a reference. If an object's data is changed, that change will be visible through other references. Once you understand that copying a reference isn't the same as copying an object, the rest falls into place reasonably easily.
Person is a reference type, so no matter whether you use ref, out or nothing, you will always be able to modify it inside the method. You never pass the real person object to the method, you are passing the pointer as reference but not the actual Person. The ref keyword is useful with value types (such as structs, int, float, DateTime, ...). It could also be used with reference types but only to indicate behavior but cannot enforce it. If you use it with reference types it allows you to change the object this reference is pointing to.
When you pass P to a test method you pass its location in the memory, rather than the copy of the object. Reference gets picked up in the body of the method and the original value gets modified.
Utilityclass.TestMethod cannot change the local variable p to point to a different Person object since you are not passing by reference, but it is still free to call any methods or change any properties on the object it is passed. So the Name property can be modified within Utilityclass.TestMethod.
This question has been mostly answered, but I think you might like to try out this snippet (bonus points if you try this out with ints!)
class Program
{
static void Main(string[] args)
{
Person p = new Person();
p.Name = "Class Lijo";
Utilityclass.TestMethod(p);
string classResult = p.Name;
Console.WriteLine(classResult);
Utilityclass.TestMethod2(ref p);
classResult = p.Name; // will bomb here
Console.WriteLine(classResult);
}
}
public class Utilityclass
{
public static void TestMethod(Person k)
{
k.Name = "Changed";
k = null;
}
public static void TestMethod2(ref Person k)
{
k.Name = "Changed Again!";
k = null;
}
}
When you pass a reference type argument to a method, this means that the method has direct access to that argument not to a copy of it....
So the result is Changed.