1

I have a static dictionary that is being used like a little "cache".

In some place, I create a new object and set some property of it to have a value from the dictionary.

Later, for some reasons I am encoding some string properties of the object using PropertyInfo.SetValue.

The issue is - the dictionary value is also changed.

I tried to "copy" the string before encoding it, but seems the issue is the setValue and not the string changing.

Person p = new Person();
//Cache.Countries is a static dictionary of countries
//each Country contains a few properties, not just description
p.Country = Cache.Countries[1];
encodeObj(p.Country);

The encodeObj funtion runs foreach on all object properties, which encodes all the strings on a given object.

private void encodeObj(object obj)
{
    foreach(var pi in obj.GetType().GetProperties())
    {
        object propValue = pi.GetValue(obj,null);
        if(pi.PropertyType == typeof(string) && !string,IsNullOrEmpty((string)propValue))
        {
            //the Copy is what I tried but didn't work
            string temp = string.Copy((string)propValue);
            string encoded = WebUtility.HtmlEncode(temp);
            //here is the problematic line
            //if I watch now Cache.Countries[1].<the current property info>
            //it is ok
            pi.SetValue(obj,encoded)
            //here if I watch again Cache.Countries[1].<the current property info>
            //it was changed to the encoded value!  
        }
    }
}       

How can I SetValue without changing the source dictionary?

Batsheva
  • 85
  • 1
  • 2
    You should clone `Cache.Countries[1]` prior to assigning it anywhere, otherwise you're just sharing the same object. Changing it in one place will change it everywhere. – pneuma Sep 09 '19 at 15:09
  • 4
    Why would you expect this to behave any differently? Your cache has the same reference to obj that you are working with in encodeObj. Changing any of the properties of obj will change the properties of the object in the cache because you're looking at a single instance – Jon Sep 09 '19 at 15:09
  • 2
    Consider reading carefully about *reference* types and *value* types in C#. – dymanoid Sep 09 '19 at 15:10
  • 1
    Read [What is the difference between a reference type and value type?](https://stackoverflow.com/questions/5057267/) – Dour High Arch Sep 09 '19 at 15:51

1 Answers1

0

Your encodeObj(object obj) method is setting values on obj DIRECTLY. This means that the object passed in will be modified. This is the default behavior when passing objects that are not structs or other value types (e.g most custom classes).

To prevent this, you need to clone your object either before passing into the method, or modify your method to clone the incoming object and return the clone for use to the caller.

Further reading
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-value-type-parameters

Tyler Lee
  • 2,736
  • 13
  • 24