How to making a read-only array reference?

R

rossum

Is there any way of creating a read only reference to an array? My
class includes a private array of bytes with a Property to access it.
However, I do not want users to use the returned reference to modify
the array; modifications are only allowed through the property, which
includes error checking. I have been trying to use Array.AsReadOnly()
to return a read only reference, but with very little success:

public class Foo {

private byte[] m_bytes;

public Foo() { m_bytes = new byte[] { 0x00, 0x01, 0x02 }; }

public byte[] Bytes {
get { return Array.AsReadOnly(m_bytes); }
set { /* error checking omitted */ m_bytes = value; }
}
}

This gave a compile time error:

Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<byte>' to 'byte[]'

Trying an explicit conversion didn't work either, nor did
AsReadOnly<byte>() with or without explicit conversion.

My next effort looked like:

get {
IList<byte> temp = Array.AsReadOnly<byte>(m_bytes);
return (byte[])temp;
}

This compiled fine but threw a runtime error:

Unable to cast object of type
'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Byte]' to
type 'System.Byte[]'.

Changing IList to List just gave a compile time error.

For the moment I am creating a cloned copy of the arrray and returning
that, but it is not an ideal solution as the users can amend the
cloned copy and get unexpected results when my class uses the
unchanged original. Is there anything better I could do to get a read
only array reference?

Thanks,

rossum
 
B

Barry Kelly

rossum said:
Is there any way of creating a read only reference to an array? My
class includes a private array of bytes with a Property to access it.
However, I do not want users to use the returned reference to modify
the array; modifications are only allowed through the property, which
includes error checking.

No, you can't do that. You should use a collection class instead, such
as Collection<T> (in .NET 2) or CollectionBase. These classes have
indexers to make them look more like arrays. The reason arrays aren't
recommended as properties in the Design Guidelines is for precisely the
problems you're finding now.

-- Barry
 
T

tomb

How is the user interacting with the array? If they don't need the
entire array, you could give them access to one element at a time
through a read-only property. If they are utilizing the entire array
through controls, then maybe those controls can restrict the
modifications. I like your idea of using a cloned copy - but you might
want to add some messaging to the user that changes may not be accepted
by the application. And you could add some kind of validation to see if
maybe you actually do want to accept the changes.

T
 
J

Jeff Louie

Rossum... C# does not offer the equivalent of C++ const on a pointer.
You can
instead wrap the private array in an instance of an immutable class and
pass a
reference to the immutable wrapper object to as many clients as you
wish. You
can provide a get only indexer to the wrapper class using the syntax:

public someType this[int index]
{
get
{
...
}
}

Regards,
Jeff
For the moment I am creating a cloned copy of the arrray and returning
that, but it is not an ideal solution as the users can amend the
cloned copy and get unexpected results when my class uses the
unchanged original.<
 
C

Chris Nahr

Is there any way of creating a read only reference to an array? My
class includes a private array of bytes with a Property to access it.
However, I do not want users to use the returned reference to modify
the array; modifications are only allowed through the property, which
includes error checking. I have been trying to use Array.AsReadOnly()
to return a read only reference, but with very little success:

RTFMSDNLibrary. AsReadOnly does not return an array, it returns a
ReadOnlyCollection<T>. That does work and gives you a read-only
collection... however, it's not an array. .NET does not support
read-only arrays, unfortunately.
 
R

rossum

Is there any way of creating a read only reference to an array? My
class includes a private array of bytes with a Property to access it.
However, I do not want users to use the returned reference to modify
the array; modifications are only allowed through the property, which
includes error checking. I have been trying to use Array.AsReadOnly()
to return a read only reference, but with very little success:

public class Foo {

private byte[] m_bytes;

public Foo() { m_bytes = new byte[] { 0x00, 0x01, 0x02 }; }

public byte[] Bytes {
get { return Array.AsReadOnly(m_bytes); }
set { /* error checking omitted */ m_bytes = value; }
}
}

This gave a compile time error:

Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<byte>' to 'byte[]'

Trying an explicit conversion didn't work either, nor did
AsReadOnly<byte>() with or without explicit conversion.

My next effort looked like:

get {
IList<byte> temp = Array.AsReadOnly<byte>(m_bytes);
return (byte[])temp;
}

This compiled fine but threw a runtime error:

Unable to cast object of type
'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Byte]' to
type 'System.Byte[]'.

Changing IList to List just gave a compile time error.

For the moment I am creating a cloned copy of the arrray and returning
that, but it is not an ideal solution as the users can amend the
cloned copy and get unexpected results when my class uses the
unchanged original. Is there anything better I could do to get a read
only array reference?

Thanks,

rossum

Thanks for all your replies. I rather suspected that this was not
possible in C# and you have confirmed it. I will probably stick with
returning a cloned copy.

rossum
 
L

liko81

rossum said:
Is there any way of creating a read only reference to an array? My
class includes a private array of bytes with a Property to access it.
However, I do not want users to use the returned reference to modify
the array; modifications are only allowed through the property, which
includes error checking. I have been trying to use Array.AsReadOnly()
to return a read only reference, but with very little success:

It's simpler than you think. The property accessor you are using allows
you to return the array element using get{}. For a read-only property,
simply do not implement a set{}. When you do this, the array reference
in _myObjects cannot be changed outside the class, under any
circumstances. Simply create an indexed property.

For example:

class MyClass {

private Object[] _myObjects;

public Object MyObjects[N]
{
get{
return _myObjects[N];
}
}

}

class myProgram
{

public static void main(string args[])
{
MyClass newClass;
Object propertyObject;

//This generates a read-only compile error
newClass.MyObjects[0] = new Object();

//This compiles successfully
propertyObject = newClass.MyObjects[0];

//You can then access public members of this object reference as
long as they aren't read-only themselves
propertyObject.SomeProperty = someValue;

//re-initializing this variable does not change the _myObjects[]
array
propertyObject = new Object();

}
}

The get{} method can also be used to expand the array (such as adding
an index that does not yet exist). Simply add code that checks the
index passed, and if it's greater than the max index of the current
array, resize the array to add a new Object() instance and return the
newly instantiated object. This way, the caller doesn't even have to
know how to use myClass to add lines.

If you want to be able to remove an index and resize the array from
outside the class, the safest method is to implement a function that
takes the index and rearranges the array without that index.
Re-initializing an indexed object would be similar. The cases I'm
working with don't require such functionality. If you do this, to make
the interface consistent I would not allow the getter to expand or add
to the array: instead I would implement an AddIndex() function of some
sort.
 
C

Chris Nahr

It's simpler than you think. The property accessor you are using allows
you to return the array element using get{}. For a read-only property,
simply do not implement a set{}. When you do this, the array reference
in _myObjects cannot be changed outside the class, under any
circumstances. Simply create an indexed property.

That works in Visual Basic but not in C#. C# only supports a single
indexed property per class, namely "this". Moreover, your "[N]"
syntax is completely unsupported in C#.

Tip: try compiling code snippets before posting them... your code
results in a screenfull of errors.
 

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