I've created a class that takes in an object as a parameter by ref. When it takes this object in it's construct it is null. Why does it stay null (uninitialized)?
// example code, not real
class Test{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
When I tried it with a different class (http://pastebin.com/PpbKEufr), it stayed null
Yes, parent will stay null regardless of what you eventually assign to the variable n. The ref keyword will pass the actual reference to n (as opposed to a copy of it) into your method, and is typically used if your method was intended to assign a new object instance to the parameter.
Inside your method, you are making a copy of the reference that n points to, in this case null. When the method completes both n and parent point to null. When later you assign to n, you haven't changed the object to which n and parent point, rather you have asked n to point to a new location, leaving parent still pointing to null.
If you were to create an instance of an object and assign it to n, then parent would point to the same object and any changes to that object's properties would be visible to your class. The same would be true if you did not pass the parameter as ref, as the reference copy also would point to the same object instance.
Hope that helps.
It is not possible to change a private member of a class that way as this would break the idea of encapsulation.
In order to change (i.e. replace) an object stored in a private field you must do so explicitly via a public property or method of that class, e.g.
class Test
{
object parent;
public Test (ref object _parent)
{
parent = _parent;
}
public object Parent
{
get { return parent; }
set { parent = value; }
}
}
object n = null;
Test t = new Test (ref n);
n = new Something ();
t.Parent = n;
This way the language makes sure that data of an object cannot (accidentally) be changed from the outside, which might lead to the strangest effects.
The ref arguments in C# refer to the instance "pointed" by the argument.
For example, if you'd change _parent in the constructor and store it in other instance, then n would change too.
In the posted code you're copying the referenced instance (null) into parent. Meaning, it copies the referenced instance into the field and not the reference of the argument itself.
For example, method that changes the ref argument:
public void M(ref object arg)
{
arg = new object();
}
And a usage example:
[Test]
public void SetReferenceArgument()
{
var myClass = new MyClass();
object arg = null;
myClass.M(ref arg);
Assert.That(arg, Is.Not.Null);
}
ref argument lets us assign an instance into the argument which will change the reference both in the of the method and in the context of the caller.
Related
Is it possible to get the declaration name of a class (dynamically) and pass it as a parameter in the constructor to set the name variable in the class itself?
Example:
public class Foo
{
public string name;
public Foo()
{
name = GetClassName();
}
}
public class SomeOtherClass
{
Foo className = new Foo();
Console.WriteLine(foo.name);
}
As result I would expect it to write: "className".
No. That is not possible. There is no way to pass in a variable name without using a parameter.
This is the closest you can get:
Foo className = new Foo(nameof(className));
That sounds like a weird requirement. A variable is nothing but a reference to an object. The name of that reference has by no means anything to do with what this variable reference. Thus the actual referenced object doesn´t know anything about its references. In fact you may have even multiple references to the same Foo-instance. So how should the instance know to which variable you refer to? So what should happen in the following example:
var f = new Foo();
var b = f;
Now you have two references to the same instance of Foo. The instance can´t know which of hose is the right, unless you provide that information to it by using a parameter (e.g. to your constructor). The thing gets even worse if you have a factory creating your Foo-instance:
void CreateFoo()
{
return new Foo();
}
// ...
var f = CreateFoo();
Now you have a further indirection, the constructor of Foo can surely not bubble though all layers in your call-stack until it reaches some assignement where it may get the actual name. In fact it´s possible that you don´t even assign your instance to anything - although this is merely a good idea:
CreateFoo(); // create an instance and throw it away
Anyway if you want to set a member of an instance to some value, you should provide that value to the instance. The answer by Patrick shows you how to do so.
The application is printing 24 but shouldn't it be printing 18 when we know that without ref keyword only a copy of object is passed and no change is made to the original object.
I have created a class called myclass and an object me. age is a public variable in class myclass.
I have set me.age as 18 and through the method show I have changed it to 24.
class Program
{
static void Main(string[] args)
{
myclass me = new myclass();
me.age = 18;
show(me);
Console.WriteLine(me.age);
Console.ReadLine();
}
public static void show( myclass you)
{
you.age = 24;
}
}
class myclass
{
public int age;
}
Don't confuse the variable and what the variable points to.
When you have:
MyClass myVar = new MyClass();
MyClass myVar2 = myVar;
That will create only a single instance of an object, but 2 variables pointing to it.
The same thing is happening to your parameter: you is a copy of the variable me, but both point to the same object. So when you modify you.age, you are also modifying me.age.
In your function, if you then did
you = new myClass();
only then would me and you refer to different objects. If you did this, me would still point to the original object.
If you added ref to the parameter you, then if you did
you = new myClass();
then the variable me would be updated to point to that same object.
For objects, you need to separate the variable from what the variable points to.
It's printing the right thing.
myclass is an object, and the default behavior is to pass the reference of the object in C#, so when you don't specify anything, you pass the reference.
If you declare struct myclass though, you'll have the behavior you want, because structs aren't references by default.
You're probably confusing this with C++ classes. In C#, classes are reference types, which means that whenever you have a variable of a type that's class, that variable doesn't hold the object itself, it holds only a reference to it (you can think of it as a pointer). So, when you pass your object into a method, you actually pass a reference to that object. This means the behavior you're observing is correct.
C# also supports value types (unlike e.g. Java), which you create by using struct instead of class. If you changed myclass into a srtuct, you would get the behavior you expected.
You are confusing value types and reference types.
public void addTwo(int a)
{
a += 2;
}
...
int a = 5;
addTwo(a);
Console.WriteLine(a); // will give "5";
public void addTwo(ref int a)
{
a += 2;
}
...
int a = 5;
addTwo(ref a);
Console.WriteLine(a); // will give "7";
For reference types (anything that is defined as class instead of struct, what you are passing on is a reference to the object, not a copy. So you are in fact changing the object.
You are sending an object to your function.
Not an atomic type or a struct, therefor it is sent by reference (this is how C# works), anything you change in this object in the function will also change in the original object because it is the same.
More information about passing parameters: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx
As far as I know Class and Object are reference type.
I have below method to Change the Value
public void ChangeValue(MyClass classobj)
{
classobj.Number = classobj.Number*2;
}
I invoke the method to double the value
var myClass=new MyClass();
int myNumber = 10;
myClass.Number = myNumber;
ChangeValue(myClass);
And it will be return 20 which is fine as you can interpret it as when you make object of your class then it pass reference to method and it will update the reference values.
but my question is why its not happening for Object type. In other words why when I make object and assign some value to it like below
object myObject = new object();
string sometext = "Some object value";
myObject = sometext;
ChangeValue(myObject)
it wont change the value after executing the method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
I know the parameter of methods are value types but can not understand it have different behavior for two reference type.
You're actually doing two different things here. Object and your MyClass are indeed both reference types, which means you pass a reference to the actual object into the ChangeValue method. However, the reference that you see inside the method is a copy of the reference the caller holds. They point to the same object, so when you manipulate the object in the method the caller of the method can see your changes, but changes to the actual reference inside the method only affect the method itself.
In an attempt to summarise, objects are passed by reference, but those references are passed by value.
In your method
public void ChangeValue(object objectValue)
{
objectValue = null;
}
What you're actually doing is reassigning the reference objectValue, and that reference is a copy of the reference called myObject which the caller has. Because the method only has a copy, it can't affect the caller's reference at all.
There is a way to make this work, you have to pass the reference by reference. Which always gives me a headache, but that's what the ref keyword is for.
public void ChangeValue(ref object objectValue)
{
objectValue = null; // this is the SAME reference as the caller has, so the caller will see this change
}
However then it also has to be called that way:
ChangeValue(ref myObject);
so that it's obvious at the call site that it might come back pointing to a different object. It's important to know that, as you might still have things relying on the old value and end up in a horrible confused mess if references were pointing to different objects unexpectedly.
You pass the objectValue to the ChangeValue(object objectValue) by value and this value is a reference. Then you change this value, but not the value of the myObject.
You have to pass it as ChangeValue(ref object objectValue) to actually pass the value of reference by reference.
It's not a different behavior, you're doing different things
This will work exactly as your object example:
public void ChangeValue(MyClass classobj)
{
classobj = null;
}
And this will work as your first example(assuming you will pass MyClass instance):
public void ChangeValue(object objectValue)
{
((MyClass)objectValue).Number *= 2;
}
What realy happens here is that when you are assigning parameter (not a property or field of parameter) you are only changing that parameter's value. Original value and variable in calling code stay intact.
The same happens here:
MyClass a = new MyClass();
MyClass b = a;
a = null;
// b still contains the value created in the first line
Simply speaking, reference variables hold the pointer (memory address) of the actual value.
By changing variable's value, you are making it point to different object or null.
But when you are doing a.field=2 this means you are taking the object a is referencing to and changing it's field member value.
In this question I would like to find out if and how this is possible. This technique would seem extremely bad practice but it seems that the API (UnityEditor) that I am using, is doing something like this and I am just curious.
If there are multiple references to the same object, is it possible to instantiate a new object into the same memory slot so that all previous references point to the new object?
I figured out that the only feasible way to do so is by using unmanaged C++. Essentially the following is happening:
// Original prefab
GameObject prefab = x;
prefab.tag = "Untagged";
// A copy of the original prefab
GameObject prefabCopy = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
prefabCopy.tag = "EditorOnly"; // Change from initial value "Untagged"
Debug.Log(prefab.tag); // "Untagged" - expected
Debug.Log(prefabCopy.tag); // "EditorOnly" - expected
// Replace contents of prefab file with `prefabCopy`
PrefabUtility.ReplacePrefab(prefabCopy, prefab);
// Destroy the copy
DestroyImmediate(prefabCopy);
Debug.Log(prefab.tag); // "EditorOnly" - whoa?
Some how prefab is now pointing to a different object?
Note: Bear in mind that Unity is built on top of the Mono flavour of .NET
Since an object state is defined by field values, you can copy memory, containing field values, from one object to another, effectively "replacing" it:
public static void Replace<T>(T x, T y)
where T : class
{
// replaces 'x' with 'y'
if(x == null) throw new ArgumentNullException("x");
if(y == null) throw new ArgumentNullException("y");
var size = Marshal.SizeOf(typeof(T));
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(y, ptr, false);
Marshal.PtrToStructure(ptr, x);
Marshal.FreeHGlobal(ptr);
}
Note that this code requires [StructLayout(LayoutKind.Sequential)] (or LayoutKind.Explicit) attribute defined for a class.
You could do that if you embed your object into another one that is used to access the object.
class ObjectReference<T>
where T : new()
{
private T _obj = new T();
public void CreateNewObject()
{
_obj = new T();
}
public T Value { get return _obj; }
}
Now you can create multiple references to an object of type ObjectReference and only change the local object. The "real" object would be accessed through the Value property
A slightly different approach is that you create a wrapper that implements the same interface as your "real" object, thus making this wrapping transparent.
interface ISomeInterface
{
string PropertyA { get; set }
void MethodB (int x);
}
class TheRealObject : ISomeInterface
{
public string PropertyA { get; set }
public void MethodB (int x)
{
Console.WriteLine(x);
}
}
class Wrapper : ISomeInterface
{
TheRealObject _obj = new TheRealObject();
public string PropertyA
{
get { return _obj.PropertyA; }
set { _obj.PropertyA = value; }
}
public void MethodB (int x)
{
_obj.MethodB(x);
}
public void CreateNewObject()
{
_obj = new TheRealObject();
}
}
Now the wrapper can be used as if it was the "real" object. You could also pass an initial instance of the "real" object in the wrapper's constructor and remove the initializer of _obj.
No, that's not possible.
To actually change all references to an object, you would have to freeze all threads in the process, and access their register sets and stack. That's what the garbage collector does, but it's not possible for regular code.
What the method most likely does is to make a deep copy of one object onto the other.
If it is a custom Class you want to reference, i think you can have all the references point to a Fake Reference...
create your class (A)
create your class Interface (IA)
Create a wrapper class based on your interface which just passes all calls to a contained object (AC)
I Added a Assignment operator so i have all A Objects as ACs.
class AC:IA
{
IA ref;
AC(IA ref)
{
this.ref = ref;
}
public void ChangeReference(IA newRef) { ref = newRef;}
public static operator = (IA assignedObj)
{
return (assignedObject is AC) ? assignedObject : new AC(assignedObj);
}
// implementation of all methods in A
public override string ToString() { return ref.ToString(); }
...
}
Now if you want, you can use the ChangeReference method to switch all to the new Reference..
in C++ you would use Reference to Reference
Best of luck
Greetings,
I get the difference between pass by value and pass by reference. But pass reference (such as array) by ref and pass array by value is something i can't seem to comprehend. How can you pass a reference by reference?
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array)
{ array = new int[] {7,8,9}; // will not work }
PassByRef(ref int[] array)
{ array = new int[] {10,11,12}; } // will work
If you pass a reference by reference you can make the variable passed in point to a new object. If you pass the reference by value you still can change the state of the object, but you can't make the variable point to a different object.
Example:
void RefByRef(ref object x)
{
x=new object(2);
}
void RefByValue(object x)
{
x=new object(2);//Only changes a local variable and gets discarded once the function exits
}
void Test()
{
object x1=1;
object x1a=x1;
RefByRef(ref x1);
//x1 is now a boxed 2
//x1a is still a boxed 1
object x2=1;
RefByValue(x2);
//x2 is still a boxed 1
}
I suggest that you check out this link. It's quite useful and contains very simple examples about Parameter passing in C#.
Reference parameters don't pass the values of the variables used in the function member invocation - they use the variables themselves. Rather than creating a new storage location for the variable in the function member declaration, the same storage location is used, so the value of the variable in the function member and the value of the reference parameter will always be the same. Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. Let's look at our previous examples, just changing the parameter to be a reference parameter:
void Foo (ref StringBuilder x) {
x = null;
}
...
StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (ref y);
Console.WriteLine (y==null); // will write TRUE
IN YOUR EXAMPLE
int[] myArray = {1,2,3};
PassByVal(myArray);
PassByRef(ref myArray);
PassByVal(int[] array){
// the function copy the value of the pointer in a new location of memory
// the "copied" pointer still points to the array 123
// now you are modifying the object pointed by THE COPY of the pointer
// the original pointer still points to array 123
// the copy of the pointer will point to array 456
array = new int[] {7,8,9};
} // will not work
PassByRef(ref int[] array){
// here you are passing the pointer without creating a copy of it in a
// new location of memory
// we have not a original pointer and a "copyed" pointer
// we have only the original pointer and now whe point it to array 10,11,12
array = new int[] {10,11,12};
} // will work
In order to answer your question let's first look at ValueTypes
A ValueType holds the Value. That is it does not in turn point to another memory location that holds the value but rather it's memory location is the value.
so
int i = 10;
int j = i;
What happens here is that a copy of the value of i is assigned to j. They both have the same value but they are different locations in memory. In oter words, each time you assign a valuetype to another valuetype, a copy is made.
Contract this with ReferenceTypes.
object o = 10;
object p = o;
because o is a ReferenceType o points to a memory location that holds the value of 10 (it is really boxed but I'll keep it simple). In the next line p now points to the same memory location. In other words, reference tyes have two things going.
1. An address pointer
2. The actual memory location (that address points to) that holds the actual "thing".
If you get it do far, then we can move on the passing by value and by reference.
In C# parameters are passed by value. So if you're passing a valueType to a method that expects a valuetype parameter, then
int i = 10;
SomeMethod(i);
Console.WriteLine(i);
static void SomeMethod(int value)
{
value = 20;
}
When the call is made to SomeMethod a copy of the value of i is sent to the method. If the method manipulates the parameter, it does not affect the original variable i. So what you'll see in the console window is 10;
contract this with reference types;
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
Since c is a reference type. And C# passes parameters by value. a copy of the "value" of the reference is passed. That is the value of the Address c is pointing to is passed. In the method, since the address is the same (it's a copy but it points to the same memory location), the method is able to manipulate the state of object. So what you'll see in the console window is "John" and not "Mike".
However, if the method attempts to assign another instance to the parameter (called "customer" in this case). then things change.
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(c);
Console.WriteLine(c.Name);
}
static void SomeMethod(Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
Notice that in the method we create a new instance of a Customer and assign it to the parameter customer and we set the name of this new instance to "John". What we'll see in the console window is "Mike" and not john.
That is because a copy of the original variable (c) was made before passing it to the method. While now in the method we have another address and then manipulate that new address so the original instance is untouched. Make sense?
Ok, if that makes sense. then what if we actually wanted the SomeMethod to be able to do what we attempted to do? Well, then the parameter can't be passed by value but it has to be passed by reference. Meaning that the variable c and the two part (the value of address it is pointing and the address itself) are being passed. So now you're passing a reference type by reference.
class Program
{
static void Main(string[] args)
{
Customer c = new Customer() { Name = "Mike" };
SomeMethod(ref c);
Console.WriteLine(c.Name);
}
static void SomeMethod(ref Customer customer)
{
customer = new Customer();
customer.Name = "John";
}
}
class Customer
{
public string Name { get; set; }
}
This may seem a bit confusing, but it's really not that tricky. When you assign an instance of a reference type to a variable, you could say the value of that variable will be a reference to the object, not the object itself. When you pass that variable by value to another method, you are passing a copy of the reference. The called method will "see" the same instance as the calling code does. If you instead pass the variable by reference, the calling method gets to see the same copy of the reference as the calling code does.
The difference in behavior between these to is that when you pass the variable by reference, the called method might assign another reference to the variable (make it reference another instance of the same type), and the calling code will see this change. Unless you make such assignments, there is no need to use ref.