Well, first off, .net has introduced IReadOnlyList and IReadOnlyDictionary which address this problem for generics(which is preferable to a base array), previously you would have to had created your own interface in order to see the same performance with the same restriction.
The basic problem, and no, it's not limited to arrays, is that you want to provide a method of accessing a bunch of items without requiring that they be iterated, but you don't want the consumer of your API to be adding or deleting items -- but previously all of the built in interfaces that allow what you want, also allowed what you don't want.
The suggested solution is both inefficient (creating a clone is slow) and misleading -- the consumer gets an array that he thinks he can modify and have that effect the object that returned it. Ie he thinks if he adds an element and then calls the property again, he will get an array with p+1 items. He also expects that o.ItemArray.Equals(o.ItemArray). Neither of these expectations will be true.
As a practical problem, this is no longer a problem if you can use the right version of the framework and something other than an array.
As for the performance problem...
if(o.ItemArray.Equals(o.ItemArray) || o.ItemArray.Equals(o2.ItemArray))
Creates 4 copies of a potentially large array.
Edit in response to comment:
This is not a problem specific to Arrays. List and Dictionaries are also mutable.
IList<string> lst = new List<string>();
lst.Add("hello");
lst[0]="bye";
Console.WriteLine(lst[0]);
And the above code sample shows the problems with mutable list as properties. Suppose that I had a class, Greetings, which had a list of words and phrases that you would use upon meeting someone. Hello, Hi, Hola, Hey dude, Whats up! Como esta and so forth. So, I have a property Words, and return the above lst. You can then immediately execute the 3rd line and change my "hello" to "bye" --for everyone that has a reference to that instance of the class.
But as I said, in 4.5, you would get around this by having your list be IReadOnlyLst and, using this...
return (IReadOnlyList<string>) lst;