Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How am I able to change a value inside a private read only array outside a class?

Tags:

c#

.net

Please see the code below:

public class Program
{
    private static void Main()
    {
        var c = new MonthClass();
        string[] months = (string[])c.GetMonths();
        months[0] = "Thursday";

        var d = c.GetMonths();
        Console.WriteLine(d.First());
    }
}

public class MonthClass
{
    private readonly string[] _months =
    {
        "January", "February", "March", "April","May","June","July",
        "August","September", "October", "November","December"
    };

    public IEnumerable<string> GetMonths() => _months;
}

Notice that MonthClass._months is private and read only. However, the second call to GetMonths returns Thursday as the first element of the array instead of January.

How am I able to change the value of a private read only member outside of MonthClass and how can I prevent this?

After reading the answers and doing my own research. I believe the following will resolve the issue:

private readonly string[] _months =
{
    "January", "February", "March", "April","May","June","July",
    "August","September", "October", "November","December"
};


public IEnumerable<string> GetMonths
{
    get { foreach (var month in _months) yield return month; }
}
like image 949
w0051977 Avatar asked Dec 08 '25 17:12

w0051977


1 Answers

GetMonths() returns a reference to an array. Anybody who has its return value, has a reference to the array, and they can change it.

So what if you happen also to have kept a private reference to the array that you returned from that public method? The public method returned a reference to the object. readonly applies to the reference, not to the object itself.

This code is functionally identical:

public class C {
    private readonly string[] _array = new [] { "foo" };
    public string[] GetArray() => _array;
}

public class D {
    public static void Test() {
        C c = new C();
        c.GetArray()[0] = "bar";
    }
}

Here's how to fix it:

public ReadOnlyCollection<String> GetMonths() {
    return Array.AsReadOnly(_months);
}

That will return a different actual object, one that actually forbids writing -- not just a differently typed reference to the same array.

You may as well return ReadOnlyCollection instead of IEnumerable, since the actual object you're returning is indexable.

If you want to return an object that's mutable, but doesn't allow anyone to change the private _months field, this works:

public List<string> GetMonths() => _months.ToList();

And so does this:

var mutableMonths = c.GetMonths().ToList();

I implore you not to name a property "Get", and not to return a new object from a property. This is an appropriate case for a method.

like image 157
15ee8f99-57ff-4f92-890c-b56153 Avatar answered Dec 11 '25 07:12

15ee8f99-57ff-4f92-890c-b56153



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!