Read-Only Hashtable - how?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hashtable has a property IsReadOnly. i can't figure out how this gets set.
It's not a property you can set directly and i can't find a constructor that
takes an RO parameter. How on earth does it get set?

More generally, is there a way i can expose a stanadrd collection as
read-only? Manager should be able to load and modify Employees internally but
when exposing it to the caller it should not let the caller change it.

i can do this by writing my own custom class (and maybe inheriting
ReadOnlyCollectionBase) but i'd rather use a built in class if one is
available

i considered keeping a normal Hashtable (or somesuch) internally and
re-casting it or cloning it to something readonly to expose but didn't find
anything suitable

i thought for a second i could add the keyword readonly in front of the
variable declaration but i have since learned the error of my ways

So is there a way to use one of the built-in collections to expose read-only
data or do i need to create my own?

-baylor
 
baylor said:
Hashtable has a property IsReadOnly. i can't figure out how this gets set.
i can do this by writing my own custom class (and maybe inheriting
ReadOnlyCollectionBase) but i'd rather use a built in class if one is
available

You will need to proxy the collection.


Note that you need to trust the caller not to downcast the Values, Keys,
GetEnumerator(), ... if you don't want to proxy those.

Below is some exaple code you can use as:

IDictionary dict = some_dictionary_which_may_be_read_write;
return ReadOnlyDictionary.Make(dict);


class ReadOnlyDictionary: IDictionary
{
public static IDictionary Make(IDictionary dict)
{
if ( dict.IsReadOnly )
return dict;
else
return new ReadOnlyDictionary(dict);
}
class Immutable: NotSupportedException
{ public Immutable(): base("Immutable data-structure") {} }
protected IDictionary Parent;
protected ReadOnlyDictionary(IDictionary dict)
{ this.Parent = dict; }
#region IDictionary Members
public bool IsReadOnly { get { return true; } }
/* IDictionaryEnumerator doesn't provide mutation
so we can reuse parents without proxy
if we trust the caller not to downcast
to the real type
*/
public IDictionaryEnumerator GetEnumerator()
{ return Parent.GetEnumerator(); }
public object this[object key]
{
get { return Parent[key]; }
set { throw new Immutable(); }
}
public void Remove(object key) { throw new Immutable(); }
public bool Contains(object key) { return Parent.Contains(key); }
public void Clear() { throw new Immutable(); }
/* ICollection doesn't provide mutation
so we can reuse parents without proxy
if we trust the caller not to downcast
to the real type
*/
public ICollection Values { get { return Parent.Values; } }
public void Add(object key, object value) { throw new Immutable(); }
/* ICollection doesn't provide mutation
so we can reuse parents without proxy
if we trust the caller not to downcast
to the real type
*/
public ICollection Keys { get { return Parent.Keys; } }
public bool IsFixedSize { get { return Parent.IsFixedSize; } }
#endregion

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

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

public override bool Equals(object obj)
{ return Parent.Equals(obj); }
public override int GetHashCode() { return Parent.GetHashCode(); }
public override string ToString() { return Parent.ToString(); }
}
So is there a way to use one of the built-in collections to expose read-only
data or do i need to create my own?

Just use a proxy, it's rather convinient.

Remember, that this doesn't guard you against people using reflection or
whatnot. The only alternative is to copy your returned hashtable's, that
way you don't *care* if the caller edits it.

return new Hashtable(dict);

But that's awfully expensive.
 
Back
Top