I need to have an instance which is the pointer of another instance. Basically, I will have two instances called A and B created from the same class. whenever I will change an attribute of A instance the B instances attribute will be changed. Basically, the attributes will have the same address on the memory.
I just want to reach the same object with different variable names. Whenever one of them will be edited, the other one should be edited too.
How can I do that in Unity with c#?
I will have 2 instances with same type. Whenever one of them will be
edited, the other one should be edited too.
I just want to reach the same object with different variable names.
You can use properties to fake pointing to another variable. This is easily done with the get and set accessors.
Let's say that the main variable is named score:
public int score;
You can point to the score variable with two other variables:
public int scoreWithDifferentName1
{
get { return score; }
set { score = value; }
}
and
public int scoreWithDifferentName2
{
get { return score; }
set { score = value; }
}
Now, you can change the score variable or access it with those two property variables above:
scoreWithDifferentName1 = 0;
Debug.Log(scoreWithDifferentName1);
Or
scoreWithDifferentName2 = 3;
Debug.Log(scoreWithDifferentName2);
Another option is to use IntPtr but this is not necessary. The C# property feature is enough to give you what want. This works both for value and reference types.
This seems like a design question of how you want your classes to look like and what are their responsibilities. I'm not sure what is the purpose of the class that you're talking about but the obvious solution here is an attribute with a static modifier.
Adding a static attribute to your class will insure it will have the same value across all instances, i.e.:
public class ClassX
{
public static string staticVar = "This is a static string";
private string var1;
}
It sounds like you're describing the regular way reference types work in C#:
public class MyClass
{
public string Name {get;set;}
}
void Test()
{
var a = new MyClass();
a.Name = "Test";
var b = a;
Console.WriteLine(a.Name); // "Test"
Console.WriteLine(b.Name); // "Test"
b.Name = "MossTeMuerA";
Console.WriteLine(a.Name); // "MossTeMuerA"
Console.WriteLine(b.Name); // "MossTeMuerA"
Mutate(a);
Console.WriteLine(a.Name); // "John"
Console.WriteLine(b.Name); // "John"
}
void Mutate(MyClass myClass)
{
myClass.Name = "John";
}
Example 1
Note that if you want to modify which class instance the variable passed to a method points to, you need to use the ref keyword:
void Test()
{
var a = new MyClass();
a.Name = "Test";
var b = a;
Console.WriteLine(a.Name); // "Test"
Console.WriteLine(b.Name); // "Test"
Mutate(ref a);
Console.WriteLine(a.Name); // "John"
Console.WriteLine(b.Name); // "Test"
}
void Mutate(ref MyClass myClass)
{
myClass = new MyClass();
myClass.Name = "John";
}
Example 2
There is also another keyword, out, which allows a method to instantiate an object in the scope of the caller by passing in the variable you want to populate:
void Test()
{
MyClass a;
Instantiate(out a);
Console.WriteLine(a.Name); // "John"
}
void Instantiate(out MyClass myClass)
{
myClass = new MyClass();
myClass.Name = "John";
}
Example 3
Related
I have a product class that looks something like this -
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
}
I have an extension class that looks like this
public static class ProductExtension
{
public static void FixProduct(this Product product)
{
product = new Product(){Name = product.Name.ToUpper()};
//product.Name is now UPPERCASE
}
}
In my Main method I have -
static void Main(string[] args)
{
Product p = new Product() {ProductId = 1, Name = "steve"};
p.FixProduct();
System.Console.WriteLine(p.Name);
}
This prints "steve" and not what I wanted it to print: "STEVE".
Why doesn't the assignment in the extension method work?
I suggest a small change to follow a fluent interface pattern. Instead of void, return the new product instead. Don't use ref, that is weird.
public static class ProductExtension
{
public static Product FixProduct(this Product input)
{
return new Product
{
Name = input.Name.ToUpper(),
Id = input.Id
}
//product.Name is now UPPERCASE
}
}
Then use it like this:
static void Main(string[] args)
{
var p = new Product()
{
ProductId = 1,
Name = "steve"
}
.FixProduct();
System.Console.WriteLine(p.Name);
}
A neat advantage of this approach is (if you think you will need it) you can support several product classes while preserving their precise type, e.g.:
public static class ProductExtension
{
public static T FixProduct<T>(this T input) where T: Product, new
{
return new T
{
Name = input.Name.ToUpper(),
Id = input.Id
}
}
}
Now you could use it on any derived product class while keeping exactly the same syntax.
class DeluxeProduct : Product
{ }
static void Main()
{
var p = new DeluxeProduct
{
Id = 1,
Name = "Steve"
}
.FixProduct();
Console.WriteLine(p.GetType().Name)); //outputs "DeluxeProduct"
}
Now on the other hand, if all you want to do is "fix" the product's name, you could just wrap it in a property.
class Product
{
private string _name;
public int Id { get; set; }
public string Name
{
get { return _name; }
set { _name = value.ToUpper(); } //Automatically "fix" it the moment you set it
}
}
...and then you don't need an extension method at all.
Extension methods cannot be used that way. In your method you create a new instance of Product and then assign it to product which is a local reference to the passed object, and not the original reference p.
When you first enter the function what you have is two references referencing the same object in memory.
Then just before exiting the method you have two objects, one referred by each reference, with the product reference, referencing a local variable being cleaned by the GC at the end of the method call.
Solutions:
To correct this and have it closest to what you were trying to do,
change your method to get a ref parameter:
public static void FixProduct(ref Product product)
{
product = new Product() { Name = product.Name.ToUpper() };
//product.Name is now UPPERCASE
}
and then:
ProductExtension.FixProduct(ref p);
I believe a better approach all together will be (by having it a
member function or an extension method) to update the object instead
of instantiating a new one:
public static void FixProduct(this Product product)
{
product.Name = product.Name.ToUpper();
}
In your extension method, you are assigning a new Product to the variable product. This doesn't end up affecting the original referenced Product.
Modify the method to the one below to set the name on the original passed in object.
public static void FixProduct(this Product product)
{
product.Name = product.Name.ToUpper();
}
Parameters are passed by value unless they are ref or out. this doesn't change that. You can understand this syntactically because ref and out require a variable reference; otherwise only an expression is required.
Unfortunately, you can't combine this with ref or out.
You can change the value of any parameter variable, though, except in the case of ref or out, it's best avoided or limited to quick touch-ups to the passed-in value that simplify later algorithmic code.
A method is permitted to assign new values to a value parameter. Such
assignments only affect the local storage location represented by the
value parameter—they have no effect on the actual argument given in
the method invocation.
— C# Language Specification
So, the assignment does work, just not in the ref or out way.
public class ABC
{
public int x;
public int y;
}
ABC _prevABC;
ABC abc;
public void A()
{
_prevABC = new ABC();
_prevABC = abc;
abc.x = 10;
}
public void B()
{
abc = _prevABC;
}
In above methods I called A and then B , even then abc.x value is 10 which I updated in A.
So it seems even though I created new Object of ABC and assigning with = its just passing reference.
How to assign with out passing reference?
_prevABC = abc line is making you problem, you assign reference of abc to _prevABC.
If your class actually holds only some values like in example you gave you could use struct because it assigns values instead reference.
If you want to keep class then you could do something like this:
_prevABC = new ABC();
_prevABC.x = abc.x;
I've recently been looking into constructors, Im currently trying to pass a object to another class file, The way im doing it is like this:
class Program
{
static void Main(string[] args)
{
Class1 objPls = new Class1();
objPls.nameArray[0] = "jake";
objPls.nameArray[1] = "tom";
objPls.nameArray[2] = "mark";
objPls.nameArray[3] = "ryan";
Echodata form2 = new Echodata(objPls);
}
}
class Class1
{
public string[] nameArray = new string[3];
}
class Echodata
{
public Class1 newobject = new Class1();
public Echodata(Class1 temp)
{
this.newobject = temp;
}
// so now why cant i access newobject.namearray[0] for example?
}
Problem is i cant access the object to get into the array..
What methods of passing objects are there? I was told this is roughly a way to do it and have been experimenting for a while to no avail.
Not sure what it is you cannot do. For example your code with this modification works, or at least compiles.
class echodata
{
public Class1 newobject = new Class1();
public echodata(Class1 temp)
{
this.newobject = temp;
}
// so now why cant i access newobject.namearray[0] for example?
// What kind of access do you want?
public void method1()
{
newobject.nameArray[0] = "Jerry";
}
}
You have an issue where your code will throw an error when trying to set the "ryan" string on the fourth index of the array. You initially set the array to be of length 3.
In your EchoData class you can access the nameArray object without an issue but you must be accessing it within a method or in the constructor. You cannot be manipulating it's content outside of these.
Keep in mind that within your EchoData class you will not see the values you set inside of your Main method.
It's hard to tell since you haven't included a complete, compilable sample, and you haven't explained exactly what "can't access" means (do you get an error? what is it?)
However, my guess is that you are attempting to access the passed in objects fields from the class level based on your code.
ie, you are trying to do this:
class Echodata
{
public Class1 newobject; // you don't need to initialize this
public Echodata(Class1 temp)
{
this.newobject = temp;
}
newobject.newArray[0] = "Can't do this at the class level";
}
You can only access nameArray from within a member method.
class Echodata
{
public Class1 newobject; // you don't need to initialize this
public Echodata(Class1 temp)
{
this.newobject = temp;
}
public void DoSOmething() {
newobject.newArray[0] = "This works just fine";
}
}
I don't understand one thing about passing parameters to methods in c#. From what I see objects in c# sometimes behave like the have been passed by reference and once as if they were passed by value. In this code I pass to method() one by reference and once by value. Both of these execute as expected. But when I created Update() and pass an object by value I see it behaving like it is updating original object.
Why do I update original object with Update(myString input) but do not update it with method(myString input)?
This is illogical!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ClassPassing
{
class Program
{
static void Main(string[] args)
{
myString zmienna = new myString();
Update(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
zmienna.stringValue = "This has run in main";
zmienna.stringValue2 = "This is a help string";
method(zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
method(ref zmienna);
Console.WriteLine(zmienna.stringValue);
Console.WriteLine(zmienna.stringValue2);
Console.ReadLine();
}
static void method(myString input)
{
input = new myString();
}
static void method(ref myString input)
{
input = new myString();
}
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
}
public class myString
{
public string stringValue { get; set; }
public string stringValue2 { get; set; }
public myString() { stringValue = "This has been just constructed"; this.stringValue2 = "This has been just constructed"; }
}
}`
You have to understand your code:
static void method(myString input)
{
input = new myString();
}
Here you pass reference to object by value
static void method(ref myString input)
{
input = new myString();
}
Here you pass reference to object by reference
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
Here again you pass reference to object by value
Now:
When you pass object reference by value, you can change the contents of the object, but you cannot change the reference itself (assign it to another object).
When you pass object reference by reference, you can both change the contents of the object and you can modify the reference itself (assign it to another object).
The real passing by value in C# occurs only in case of simple (int, float, etc.) types and in case of structs:
class Program
{
public struct MyStruct
{
public int i;
}
public class MyClass
{
public int i;
}
public static void Modify(MyStruct s)
{
s.i = 99;
}
public static void Modify(MyClass c)
{
c.i = 99;
}
public static void Main(string[] args)
{
MyStruct myStruct = new MyStruct();
myStruct.i = 20;
MyClass myClass = new MyClass();
myClass.i = 20;
Modify(myStruct);
Modify(myClass);
Console.WriteLine("MyStruct.i = {0}", myStruct.i);
Console.WriteLine("MyClass.i = {0}", myClass.i);
Console.ReadKey();
}
}
Result:
MyStruct.i = 20
MyClass.i = 99
In this case, MyStruct's value remained unchanged, because it was passed to a function by value. On the other hand, MyClass's instance was passed by reference and that's why its value changed.
Objects aren't passed at all.
For expressions of a reference type (classes, interfaces etc) references are passed - by value by default, but the variables are passed by reference if you use ref.
It's important to understand that the value of zmienna isn't an object - it's a reference. Once you've got that sorted, the rest becomes simple. It's not just for parameter passing either - it's for everything. For example:
StringBuilder x = new StringBuilder();
StringBuilder y = x;
y.Append("Foo");
Console.WriteLine(x); // Prints Foo
Here the values of x and y are references to the same object - it's like having two pieces of paper, each of which has the same street address on. So if someone visits the house by reading the address written on x and paints the front door red, then someone else visits the same house by reading the address written on y, that second person will see a red front door too.
See my articles on reference and value types and parameter passing for more details.
There may be multiple questions to answer here, but regarding your last one:
"Why do I update original object with Update(myString input) but do not update it with method(myString input)?"
Here, you are creating a new instance of the myString class and not referencing the original that was passed to the method as a parameter. So if you change the value of input.stringValue2 inside the method, you will lose the value once you leave the method.
static void method(myString input)
{
input = new myString();
}
But here you are referencing the original instance passed to it. When you leave this method, the original myString instance will retain the value of stringValue2.
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
Imagine computer memory as a set of boxes, and that you can give them names using labels.
myString zmienna = new myString();
Here you allocate a box with an instance of myString in it, and have a label zmienna pointing to it. Then:
static void method(myString input)
{
input = new myString();
}
In this method, input is an another label. Calling the method you first make the label input point to the same box, with the initial instance. However in the method's body you allocate another box, and change the label input to point to that new box. Nothing is being done with the first box, and nothing is being done with zmienna label.
static void method(ref myString input)
{
input = new myString();
}
Here, because of the ref keyword you're not only passing the whereabouts of the first "memory box", but you give the actual label. So this method's body updates your label zmienna to point to a newly created box, with a second instance of myString. The first box is being forgotten, as no labels point to it.
static void Update(myString input)
{
input.stringValue2 = "This has run in update method";
}
In this case, you pass the address of the first box, in exactly the same manner as in the first method. So you have two labes: zmienna and input - both pointing to the same box. Therefore input.stringValue2 accesses the field stringValue2 in the same box that is pointed by zmienna.
A precise term actually used is reference instead of label term I'm using in this explanation. I somehow find that many people find it easier to comprehend this way :)
Say I have a simple class like this:
public class ReferenceChanger<T>
{
public T SavedElement { get; private set; }
public ReferenceChanger(T elementToSave)
{
SavedElement = elementToSave;
}
// This method would change the original variable (given as a constructor argument)
public void SetNewReference(T newElement)
{
SavedElement = newElement;
}
}
This class saves an element given to its constructor, whatever element is. However, the "SavedElement" (its backing field) is a reference to the object given at the time of instance creation.
Is there any way to save a reference to a variable (as with using ref keyword), so that if the original item passed to the constructor changes, the SavedElement would automatically reflect the change, almost as if the object was passed with the ref keyword? (Even if I use the ref keyword, I would not be able to save the reference that way.)
Updated to make intentions more clear:
public class ExampleClass
{
public List<int> Numbers { get; set; }
}
public static void Main()
{
ExampleClass temp = new ExampleClass();
temp.Numbers = new List<int>() { 1, 2, 3 };
ReferenceChanger<List<int>> changer = new ReferenceChanger<List<int>>(temp.Numbers);
// Here, a reference to the List<int> instance (containing 1,2,3) is stored in changer's SavedElement
// Then I do this:
changer.SetNewReference(new List<int>() { 5, 6, 7 });
// Now, only changer's SavedElement was changed, but temp's property Numbers was not changed.
// Is there a way to change the temp's property Numbers from the changer?
}
Sounds like you're looking for TypedReference and the __makeref keyword.
Warning: they're poorly documented and not in the standardized part of C#.
There's a lot more information in this question.
All classes in C# are reference objects so what you have coded should update the value of SavedElement. However, if T is a primitive type (e.g., int, string, etc.), this would not work since these are set by value. You would need to put a constraint on T to make sure it's a class.
You cannot normally capture a reference to a variable and store it as a property. One hackish solution (not really suggesting it's a good idea, I'd explore other avenues first) is to capture it in a closure and pass the closure around. Closures capture variables, not values. As a result, changes to variables can be observed elsewhere. For example, given
class Foo
{
public int Baz { get; set; }
}
class Bar
{
private Func<Foo> fooGetter;
public Bar(Func<Foo> fooGetter)
{
this.fooGetter = fooGetter;
}
public void Do()
{
Console.WriteLine(fooGetter().Baz);
}
}
You can have
Foo foo = new Foo() { Baz = 1 };
Bar bar = new Bar(() => foo);
bar.Do();
foo = new Foo() { Baz = 2 };
bar.Do();
Changes to the variable foo are observed, since that is what the caller enclosed in the lambda. Had the caller simply said () => new Foo(), you would (of course) not observe any changes.