How to create a generic readonly collection?

C

cody

I know I can use ArrayList.ReadOnly() to create a readonly version of it,
but how can I achive a similar thing with a generic collection of .NET 2.0?
 
H

Helge Jensen

cody said:
I know I can use ArrayList.ReadOnly() to create a readonly version of it,
but how can I achive a similar thing with a generic collection of .NET 2.0?

Implement a proxy for the relevant collection, which throw's on mutation.

Here is an example on the .NET1.1 IDictionary, I haven't changed to
..NET2 yet -- you should be able to write one for IDictionary<> in .NET2
yourself.

using System.Collections;

class Immutable: Exception
{ public Immutable(): base("Attempt to change immutable object") {} }

/// <summary>
/// Provide immutable access to a dictionary.
/// </summary>
/// <remarks>
/// In JAVA, iterators, as well as the key- and value- parts, of a
dictionary
/// (called Map) allows mutation, so in JAVA a much more elaborate proxying
/// is required.
/// </remarks>
class ImmutableIDictionary: IDictionary
{
protected readonly IDictionary proxied;
public ImmutableIDictionary(IDictionary proxied) {
if ( proxied == null )
throw new ArgumentException(
"Cannot proxy uninstantiated IDictionary", "proxied");
this.proxied = proxied;
}
#region IDictionary Members
public bool IsReadOnly { get { return true; } }
public IDictionaryEnumerator GetEnumerator()
{ return proxied.GetEnumerator(); }
public object this[object key]
{ get { return proxied[key]; } set { throw new Immutable(); } }
public void Remove(object key) { throw new Immutable(); }
public bool Contains(object key) { return proxied.Contains(key); }
public void Clear() { throw new Immutable(); }
public ICollection Values { get { return proxied.Values; } }
public void Add(object key, object value) { throw new Immutable(); }
public ICollection Keys { get { return proxied.Keys; } }
public bool IsFixedSize { get { return true; } }
#endregion

#region ICollection Members
public bool IsSynchronized { get { return proxied.IsSynchronized; } }
public int Count { get { return proxied.Count; } }
public void CopyTo(Array array, int index) { proxied.CopyTo(array,
index); }
public object SyncRoot { get { return proxied.SyncRoot; } }
#endregion

#region IEnumerable Members
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
IEnumerable e = proxied;
return e.GetEnumerator();
}
#endregion
}
 
M

Matthias Schack

Thanks for the answer.

So that means there is no predefined method for getting a readonly List<> in
..NET 2.0?

This is very bad. Since .NET lacks the const modifier like in C++ there
should at least be a simple solution for that without having to write
readonly wrappers for all collection classes all the time by myself :(

Helge Jensen said:
I know I can use ArrayList.ReadOnly() to create a readonly version of it,
but how can I achive a similar thing with a generic collection of .NET
2.0?

Implement a proxy for the relevant collection, which throw's on mutation.

Here is an example on the .NET1.1 IDictionary, I haven't changed to
.NET2 yet -- you should be able to write one for IDictionary<> in .NET2
yourself.

using System.Collections;

class Immutable: Exception
{ public Immutable(): base("Attempt to change immutable object") {} }

/// <summary>
/// Provide immutable access to a dictionary.
/// </summary>
/// <remarks>
/// In JAVA, iterators, as well as the key- and value- parts, of a
dictionary
/// (called Map) allows mutation, so in JAVA a much more elaborate proxying
/// is required.
/// </remarks>
class ImmutableIDictionary: IDictionary
{
protected readonly IDictionary proxied;
public ImmutableIDictionary(IDictionary proxied) {
if ( proxied == null )
throw new ArgumentException(
"Cannot proxy uninstantiated IDictionary", "proxied");
this.proxied = proxied;
}
#region IDictionary Members
public bool IsReadOnly { get { return true; } }
public IDictionaryEnumerator GetEnumerator()
{ return proxied.GetEnumerator(); }
public object this[object key]
{ get { return proxied[key]; } set { throw new Immutable(); } }
public void Remove(object key) { throw new Immutable(); }
public bool Contains(object key) { return proxied.Contains(key); }
public void Clear() { throw new Immutable(); }
public ICollection Values { get { return proxied.Values; } }
public void Add(object key, object value) { throw new Immutable(); }
public ICollection Keys { get { return proxied.Keys; } }
public bool IsFixedSize { get { return true; } }
#endregion

#region ICollection Members
public bool IsSynchronized { get { return proxied.IsSynchronized; } }
public int Count { get { return proxied.Count; } }
public void CopyTo(Array array, int index) { proxied.CopyTo(array,
index); }
public object SyncRoot { get { return proxied.SyncRoot; } }
#endregion

#region IEnumerable Members
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
IEnumerable e = proxied;
return e.GetEnumerator();
}
#endregion
}

--
Helge Jensen
mailto:[email protected]
sip:[email protected]
-=> Sebastian cover-music: http://ungdomshus.nu <=-
 
H

Helge Jensen

Matthias said:
Thanks for the answer.

So that means there is no predefined method for getting a readonly List<> in
.NET 2.0?

I am not qualified to answer that, since I haven't used 2.0 yet, *but*
since .NET1.1 doesn't have it, and I haven't read about it being
introduced in .NET2, and since you asked (I suppose you've looked in the
docs), there quite possibly aren't any.
This is very bad. Since .NET lacks the const modifier like in C++ there
should at least be a simple solution for that without having to write
readonly wrappers for all collection classes all the time by myself :(

Aaaah, lots of things are far worse, besides const comes with just about
as many problems as it solves (hence the discussion about whether it's
good or bad).

Really, ICollection does not provide mutation, that leaves IList and
IDictionary from .NET1.1 and (to my poor knowledge) IList<>,
IDictionary<> and ISet<> from .NET2. All in all 5 classes.

Just be glad you're not in JAVA, where writing a readonly proxy is much
more complicated.
 
W

Willy Denoyette [MVP]

List.AsReadOnly retuns a read-only wrapper arround the current List.


Willy.

Matthias Schack said:
Thanks for the answer.

So that means there is no predefined method for getting a readonly List<>
in
.NET 2.0?

This is very bad. Since .NET lacks the const modifier like in C++ there
should at least be a simple solution for that without having to write
readonly wrappers for all collection classes all the time by myself :(

Helge Jensen said:
I know I can use ArrayList.ReadOnly() to create a readonly version of it,
but how can I achive a similar thing with a generic collection of .NET
2.0?

Implement a proxy for the relevant collection, which throw's on mutation.

Here is an example on the .NET1.1 IDictionary, I haven't changed to
.NET2 yet -- you should be able to write one for IDictionary<> in .NET2
yourself.

using System.Collections;

class Immutable: Exception
{ public Immutable(): base("Attempt to change immutable object") {} }

/// <summary>
/// Provide immutable access to a dictionary.
/// </summary>
/// <remarks>
/// In JAVA, iterators, as well as the key- and value- parts, of a
dictionary
/// (called Map) allows mutation, so in JAVA a much more elaborate proxying
/// is required.
/// </remarks>
class ImmutableIDictionary: IDictionary
{
protected readonly IDictionary proxied;
public ImmutableIDictionary(IDictionary proxied) {
if ( proxied == null )
throw new ArgumentException(
"Cannot proxy uninstantiated IDictionary", "proxied");
this.proxied = proxied;
}
#region IDictionary Members
public bool IsReadOnly { get { return true; } }
public IDictionaryEnumerator GetEnumerator()
{ return proxied.GetEnumerator(); }
public object this[object key]
{ get { return proxied[key]; } set { throw new Immutable(); } }
public void Remove(object key) { throw new Immutable(); }
public bool Contains(object key) { return proxied.Contains(key); }
public void Clear() { throw new Immutable(); }
public ICollection Values { get { return proxied.Values; } }
public void Add(object key, object value) { throw new Immutable(); }
public ICollection Keys { get { return proxied.Keys; } }
public bool IsFixedSize { get { return true; } }
#endregion

#region ICollection Members
public bool IsSynchronized { get { return proxied.IsSynchronized; } }
public int Count { get { return proxied.Count; } }
public void CopyTo(Array array, int index) { proxied.CopyTo(array,
index); }
public object SyncRoot { get { return proxied.SyncRoot; } }
#endregion

#region IEnumerable Members
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
IEnumerable e = proxied;
return e.GetEnumerator();
}
#endregion
}

--
Helge Jensen
mailto:[email protected]
sip:[email protected]
-=> Sebastian cover-music: http://ungdomshus.nu <=-
 
C

cody

Thank you that was what I was looking for.


Willy Denoyette said:
List.AsReadOnly retuns a read-only wrapper arround the current List.


Willy.

Matthias Schack said:
Thanks for the answer.

So that means there is no predefined method for getting a readonly List<>
in
.NET 2.0?

This is very bad. Since .NET lacks the const modifier like in C++ there
should at least be a simple solution for that without having to write
readonly wrappers for all collection classes all the time by myself :(

Helge Jensen said:
cody wrote:
I know I can use ArrayList.ReadOnly() to create a readonly version of it,
but how can I achive a similar thing with a generic collection of .NET 2.0?

Implement a proxy for the relevant collection, which throw's on
mutation.

Here is an example on the .NET1.1 IDictionary, I haven't changed to
.NET2 yet -- you should be able to write one for IDictionary<> in .NET2
yourself.

using System.Collections;

class Immutable: Exception
{ public Immutable(): base("Attempt to change immutable object") {} }

/// <summary>
/// Provide immutable access to a dictionary.
/// </summary>
/// <remarks>
/// In JAVA, iterators, as well as the key- and value- parts, of a
dictionary
/// (called Map) allows mutation, so in JAVA a much more elaborate proxying
/// is required.
/// </remarks>
class ImmutableIDictionary: IDictionary
{
protected readonly IDictionary proxied;
public ImmutableIDictionary(IDictionary proxied) {
if ( proxied == null )
throw new ArgumentException(
"Cannot proxy uninstantiated IDictionary", "proxied");
this.proxied = proxied;
}
#region IDictionary Members
public bool IsReadOnly { get { return true; } }
public IDictionaryEnumerator GetEnumerator()
{ return proxied.GetEnumerator(); }
public object this[object key]
{ get { return proxied[key]; } set { throw new Immutable(); } }
public void Remove(object key) { throw new Immutable(); }
public bool Contains(object key) { return proxied.Contains(key); }
public void Clear() { throw new Immutable(); }
public ICollection Values { get { return proxied.Values; } }
public void Add(object key, object value) { throw new Immutable(); }
public ICollection Keys { get { return proxied.Keys; } }
public bool IsFixedSize { get { return true; } }
#endregion

#region ICollection Members
public bool IsSynchronized { get { return proxied.IsSynchronized; } }
public int Count { get { return proxied.Count; } }
public void CopyTo(Array array, int index) { proxied.CopyTo(array,
index); }
public object SyncRoot { get { return proxied.SyncRoot; } }
#endregion

#region IEnumerable Members
IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
IEnumerable e = proxied;
return e.GetEnumerator();
}
#endregion
}

--
Helge Jensen
mailto:[email protected]
sip:[email protected]
-=> Sebastian cover-music: http://ungdomshus.nu <=-
 

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