I've created a Mutator class that looks like :
namespace Engine.Core.Mutators
{
public abstract class Mutator
{
private Dictionary<string, object> _mutatableObjects;
private Dictionary<string, object> _watchedObjects;
public Dictionary<string, object> MutatableObjects
{
get { return _mutatableObjects; }
set { _mutatableObjects = value; }
}
public Dictionary<string, object> WatchedObjects
{
get { return _watchedObjects; }
set { _watchedObjects = value; }
}
public Mutator()
{
_mutatableObjects = new Dictionary<string, object>();
_watchedObjects = new Dictionary<string, object>();
}
public virtual void Update()
{
}
public void AddMutatableObject(string key, ref byte obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref sbyte obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref short obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref ushort obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref int obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref uint obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref long obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref ulong obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref float obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref double obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref decimal obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref char obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref string obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref bool obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddMutatableObject(string key, ref object obj)
{
_mutatableObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref byte obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref sbyte obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref short obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref ushort obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref int obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref uint obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref long obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref ulong obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref float obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref double obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref decimal obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref char obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref string obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref bool obj)
{
_watchedObjects.Add(key, obj);
}
public void AddWatchedObject(string key, ref object obj)
{
_watchedObjects.Add(key, obj);
}
}
}
The idea here is to take a variable by reference and mutate it. I give the ref'd variable to a dictionary and then in a subclass, inside the Mutators Update function, the developer can mutate the variable. The desire is for this variable to, as it changes, alter the original variable that was passed in. Here's an example:
//in some other function
int a = 5;
myMutator.AddMutatableObject("myVar", ref a);
//inside the MyMutator Update Function
public override void Update()
{
if (MutatableObjects.ContainsKey("myVar"))
{
MutatableObjects["myVar"] = 10;
}
}
The desired output of a is 10, but alas it will still be 5. Is there some problem with the way I'm doing this?

1 answers
Although you're passing the int variable 'a' by reference, this doesn't cause its address to be stored in your dictionary as an object reference.
What happens is that the value of 'a' (namely 5) is 'boxed' by creating a new object on the heap into which the value of 'a' is copied and it is a reference to this boxed object which gets stored in your dictionary.
When the dictionary is updated, the integer literal 10 is again boxed on the heap and a reference to the new object replaces the earlier one as the value corresponding to the 'myVar' key. However, this doesn't affect what's stored in the variable 'a' for the reason stated above and so the output is still 5.
The only way to do what you're trying to do would be to wrap the primitive value types within ordinary classes (i.e. reference types) and then mutate those. The primitive value types themselves are immutable.
Also C# doesn't allow you to change the value of boxed objects or to access managed pointers (which are used behind the scenes to implement 'ref' and 'out' parameters) directly.
answered 2 years ago by:
17279
121
Passing the entire object instead of an individual variable works just fine. Thank you for that suggestion. I am curious to know: does passing the object into that add function create garbage? I am fairly sure it doesn't but it never hurts to check.
17279
When you pass in the entire object, the overload of AddWatchedObject() which takes an 'object' as its second parameter will be selected. A reference to this object will then be stored in the Dictionary and the Update() method will recover this object, using its key, and change its numeric field. Your original variable 'a' and the Dictionary will contain references to exactly the same object and so this change will be reflected in 'a' as well. The object itself will continue to exist as long as the variable 'a' and/or the Dictionary continue to refer to it. When this is no longer the case, the object will become eligible for garbage collection.