Returning an array in a property get returns a copy. How to get a reference?

F

Faustino Dina

Hi,

The following code is from an article published in Informit.com at
http://www.informit.com/guides/content.asp?g=dotnet&seqNum=142. The problem
is the author says it is not a good idea to return an array as a property
because it will return a copy of the array instead a reference to it. How
can I force the property to return a reference to the array? Is it only a
feature of arrays? I hope normal class objects (including collections) are
returned by reference in the same situation.

Well, I'll be glad to hear about workarounds to this array problem.
Thanks in advance
Faustino

The code follows:

class GameThing
{
private readonly int[] scoreValues = new int[22];

public GameThing()
{
for (int i = 0; i < scoreValues.Length; i++)
{
scoreValues = scoreValues.Length - i - 1;
}
}

public int[] Values
{
get { return scoreValues; }
}
}
 
D

Dennis Myrén

System.Array is a reference type, so therefore the only copy that is taking
place
is copying the address to the reference(32 bits).

System.Int32 itself is a value type, but an array(or any type of array FTM)
of System.Int32 is not.
Retrieving specific items in an array of value types though, will create a
copy of that value.
But anyway, you do not lose anything, since an Int32 and a pointer to an
Int32 are of the same size.
 
J

Jon Skeet [C# MVP]

Faustino Dina said:
The following code is from an article published in Informit.com at
http://www.informit.com/guides/content.asp?g=dotnet&seqNum=142. The problem
is the author says it is not a good idea to return an array as a property
because it will return a copy of the array instead a reference to it.
How can I force the property to return a reference to the array?

The author is talking rubbish. It's returning a reference. I do wish
people who had no idea what they're talking about didn't write articles
on those topics :(
 
B

Bruce Wood

I think that the author was trying to point out some of the pitfalls of
returning arrays from properties or methods, but got confused and ended
up, as you said, "talking rubbish."

First of all, as Jon pointed out, returning arrays from properties or
methods returns a reference, not a copy of the array. Most newbies
return arrays from properties or methods without giving it a second
thought. I know I did until FxCop pointed out that this was a dangerous
practice. Unfortunately, there is no simple, satisfactory solution to
the following problems.

If the array you're returning forms part of your object's state (which
it probably does), you're giving your caller a reference directly to
part of your internal state. This means that, after the caller has the
array, any changes the object later makes to its internal state will be
immediately reflected in the array that the caller is holding (because
it's the same array that the object is using to maintain state).

So, I call your object to, say, get a list of all of the newsgroups to
which I'm subscribed. I store that array away somewhere for later
reference. I then subscribe to a new newsgroup. Lo and behold, the new
newsgroup appears in the array that I got from the object "way back
when"! How come the array I'm holding changed magically without my
touching it? Because the object and I are sharing the same array, so an
internal change becomes an external change as well. This can lead to
nasty and subtle bugs.

Worse still, what if I decide to perform some destructive operation on
the array? After all, the object gave it to me, it's mine, so why can't
I change it? The answer is that if I change it then I'm changing the
object's internal state, since we both have references to the same
array. The object could then crash horribly because somebody messed
with its internal state directly, without going through its methods and
properties that safeguard that state. So much for encapsulation!

If you think that copying the array on return from a property or method
solves these problems, it does, but at the cost of introducing new
problems. In order to fix the above, you return a copy, not the
original array. Now your object's internal state is safe, but your
caller can do innocent things like this:

for (int i = 0; i < obj.ArrayCopyProperty.Length; i++)
{
.... do something with obj.ArrayCopyProperty ...
}

Each trip around the loop copies the array twice: the first time it
copies the array just to get its length, the second time just to pick
up element "i". If the array has 1,000,000 elements then you will
create and throw away 2,000,000 arrays in order to do this operation.
Ouch!

There are solutions that solve all of these problems, but they are
quite complex. For now, just be aware that returning an array reference
to a caller, while it's the simplest solution, comes with some dangers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top