Adam Clauss wrote:
Unfortunately Queeu<SubClasso fA> cannot be passed to a Queue<A>.
Well it's not really unfortunate -- it preseves static type-safety,
consider the following:
Queue<SubA> subaq = new Queue<SubA>();
Queue<A> aq = subaq;
aq.Enque(new A()); // oops ;)
Now, I was able to resolve the problem in this case by turning the class
which took this into a generic class itself:
class SomeClass<T> where T : A
and
class SomeOtherClass : SomeClass<SubCl assofA>
I use adapters for ICollection, assuming Bar is a subtype of Foo:
ICollection<Bar > bars = ...;
ICollection<Foo > = new UpcastedCollect ion<Bar,Foo>(ba rs);
However, I've now run into essentially the same situation with another
class. I do not believe I can use the same thing here though. The list
(Dictionary, actually) being passed into the class constructor could contain
various subclasses - not just one. Using the above solution of
class SomeOtherClass : SomeClass<SubCl assofA>
limits me to ONLY using SubClassofA objects. But in this case there are
SEVERAL subclasses of A. I can guarrantee that the Dictionary here is ONLY
used in a "read" sense (the Dictionary is not altered). In fact, the only
time the list is used is to retrieve an element (which it currently expects
to be of type A). Various operations are then performed on that object, but
the list itself is never changed.
Does that "read-only" aspect buy me any alternatives?
Well, actually yes, it makes sure no runtime casts are required.
As I see it now, my only option is to go back to the original Hashtable
object rather than Dictionary.
Below are some adapters that shows what I mean and get you started on
writing your own adapters.
#region Immutable Exceptions
public class Immutable: InvalidOperatio nException {
public readonly object Instance;
protected Immutable(objec t instance): this(instance,
string.Format(" {0} is immutable", instance)) { }
protected Immutable(objec t instance, string msg): base(msg) {
this.Instance = instance; }
public static Immutable Make(object instance) { return new
Immutable(insta nce); }
public static Immutable<T> Make<T>(T instance) { return new
Immutable<T>(in stance); }
public static Immutable Make(object instance, string msg) { return
new Immutable(insta nce, msg); }
public static Immutable<T> Make<T>(T instance, string msg) { return
new Immutable<T>(in stance, msg); }
}
public class Immutable<T>: Immutable {
public readonly new T Instance;
public Immutable(T instance, string msg) : base(instance, msg) {
this.Instance = instance; }
public Immutable(T instance) : this(instance, string.Format(" {0} is
immutable", instance)) { }
}
#endregion
#region ICollection transformation
public class TransformedColl ection<T, R> : ICollection<R>
{
public delegate R Transformer(T t);
public readonly ICollection<T> Parent;
public readonly Transformer Transform;
public readonly TransformedColl ection<R, T>.Transformer Inverse;
protected T NoInverse(R r) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
Inverse({2})", this, typeof(T), typeof(R))); }
protected R NoTransform(T t) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
Transform({2})" , this, typeof(R), typeof(T))); }
public TransformedColl ection(ICollect ion<T> parent, Transformer
transform, TransformedColl ection<R, T>.Transformer inverse)
{
this.Parent = parent;
this.Transform = transform == null ? NoTransform : transform;
this.Inverse = inverse == null ? NoInverse : inverse;
}
public TransformedColl ection(ICollect ion<T> parent, Transformer
transform): this(parent, transform, null) {}
public TransformedColl ection(ICollect ion<T> parent,
TransformedColl ection<R,T>.Tra nsformer inverse) : this(parent, null,
inverse) { }
public void Add(R r) { Parent.Add(Inve rse(r)); }
public void Clear() { Parent.Clear(); }
public bool Contains(R r) { return Parent.Contains (Inverse(r)); }
public void CopyTo(R[] rs, int index) { foreach (T t in Parent)
rs[index++] = Transform(t); }
public bool Remove(R r) { return Parent.Remove(I nverse(r)); }
public int Count { get { return Parent.Count; } }
public bool IsReadOnly { get { return Parent.IsReadOn ly; } }
public IEnumerator<R> GetEnumerator() { foreach (T t in Parent)
yield return Transform(t); }
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
public class UpcastedCollect ion<T, R> : ICollection<R> where T: R
{
public readonly ICollection<T> Parent;
public UpcastedCollect ion(ICollection <T> parent) { this.Parent =
parent; }
public void Add(R r) { Parent.Add((T)r ); }
public void Clear() { Parent.Clear(); }
public bool Contains(R r) { return r is T &&
Parent.Contains ((T)r); }
public void CopyTo(R[] rs, int index) { foreach (T t in Parent)
rs[index++] = (R)t; }
public bool Remove(R r) { return r is T && Parent.Remove(( T)r); }
public int Count { get { return Parent.Count; } }
public bool IsReadOnly { get { return Parent.IsReadOn ly; } }
public IEnumerator<R> GetEnumerator() { foreach (T t in Parent)
yield return (R)t; }
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
public class AddItem<T> : ICollection<T>
{
public readonly ICollection<T> Parent;
public readonly T Item;
public readonly IEqualityCompar er<T> Comparer;
public AddItem(ICollec tion<T> parent, T item, IEqualityCompar er<T>
comparer)
{
this.Parent = parent;
this.Item = item;
this.Comparer = comparer == null ? EqualityCompare r<T>.Default :
comparer;
}
public void Add(T t) { Parent.Add(t); }
public bool Remove(T t)
{
if (!Parent.Remove (t))
throw Immutable.Make( this, string.Format(" Cannot remove item
{0}", t));
else
return false;
}
public void Clear() { throw Immutable.Make( this,
string.Format(" Cannot clear {0}", this)); }
public bool Contains(T t) { return Comparer.Equals (t, Item) ||
Parent.Contains (t); }
public int Count { get { return Parent.Count + 1; } }
public void CopyTo(T[] array, int index)
{
array[index++] = Item;
Parent.CopyTo(a rray, index);
}
public bool IsReadOnly { get { return Parent.IsReadOn ly; } }
public IEnumerator<T> GetEnumerator()
{
yield return Item;
foreach (T t in Parent)
yield return t;
}
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
#endregion
#region IDictionary transformation
public class TransformedDict ionary<K1, V1, K2, V2> : IDictionary<K2, V2>
{
public readonly IDictionary<K1, V1> Parent;
public readonly TransformedColl ection<K1, K2>.Transformer KeyTransform;
public readonly TransformedColl ection<K2, K1>.Transformer KeyInverse;
public TransformedColl ection<V1, V2>.Transformer ValueTransform;
public TransformedColl ection<V2, V1>.Transformer ValueInverse;
public K2 DefaultKeyTrans form(K1 key) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
KeyTransform({2 })", this, typeof(K2), typeof(K1))); }
public K1 DefaultKeyInver se(K2 key) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
KeyInversem({2} )", this, typeof(K1), typeof(K2))); }
public V2 DefaultValueTra nsform(V1 value) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
ValueTransform( {2})", this, typeof(K2), typeof(K1))); }
public V1 DefaultValueInv erse(V2 value) { throw new
NotSupportedExc eption(string.F ormat("{0} does not implement {1}
ValueInverse({2 })", this, typeof(K1), typeof(K2))); }
public TransformedDict ionary(
IDictionary<K1, V1> parent,
TransformedColl ection<K1, K2>.Transformer keyTransform,
TransformedColl ection<K2, K1>.Transformer keyInverse,
TransformedColl ection<V1, V2>.Transformer valueTransform,
TransformedColl ection<V2, V1>.Transformer valueInverse) {
this.Parent = parent;
this.KeyTransfo rm = keyTransform == null ? DefaultKeyTrans form :
keyTransform;
this.KeyInverse = keyInverse == null ? DefaultKeyInver se :
keyInverse;
this.ValueTrans form = valueTransform == null ?
DefaultValueTra nsform : valueTransform;
this.ValueInver se = valueInverse == null ? DefaultValueInv erse :
valueInverse;
}
public bool ContainsKey(K2 key) { return
Parent.Contains Key(KeyInverse( key)); }
public void Add(K2 key, V2 value) { Parent.Add(KeyI nverse(key),
ValueInverse(va lue)); }
public bool Remove(K2 key) { return Parent.Remove(K eyInverse(key)) ; }
public bool TryGetValue(K2 key, out V2 v2)
{
V1 v1;
bool found = Parent.TryGetVa lue(KeyInverse( key), out v1);
if (found)
v2 = ValueTransform( v1);
else
v2 = default(V2);
return found;
}
public V2 this[K2 key]
{
get { return ValueTransform( Parent[KeyInverse(key)]); }
set { Parent[KeyInverse(key)] = ValueInverse(va lue); }
}
public ICollection<K2> Keys { get { return new
TransformedColl ection<K1, K2>(Parent.Keys , KeyTransform, KeyInverse); } }
public ICollection<V2> Values { get { return new
TransformedColl ection<V1, V2>(Parent.Valu es, ValueTransform,
ValueInverse); } }
public void Clear() { Parent.Clear(); }
public void Add(KeyValuePai r<K2, V2> kvp) { Parent.Add(new
KeyValuePair<K1 , V1>(KeyInverse( kvp.Key), ValueInverse(kv p.Value))); }
public bool Contains(KeyVal uePair<K2, V2> kvp) { return
Parent.Contains (new KeyValuePair<K1 ,V1>(KeyInverse (kvp.Key),
ValueInverse(kv p.Value))); }
public void CopyTo(KeyValue Pair<K2, V2>[] kvps, int index)
{
foreach (KeyValuePair<K 2, V2> kvp in this)
kvps[index++] = kvp;
}
public bool Remove(KeyValue Pair<K2, V2> kvp) { return
Parent.Remove(n ew KeyValuePair<K1 ,V1>(KeyInverse (kvp.Key),
ValueInverse(kv p.Value))); }
public int Count { get { return Parent.Count; } }
public bool IsReadOnly { get { return Parent.IsReadOn ly; } }
public IEnumerator<Key ValuePair<K2, V2>> GetEnumerator()
{
foreach (KeyValuePair<K 1, V1> kvp in Parent)
yield return new KeyValuePair<K2 , V2>(KeyTransfor m(kvp.Key),
ValueTransform( kvp.Value));
}
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
public class FunctionDiction ary<K, V> : IDictionary<K, V>
{
public readonly ICollection<K> Keys;
public readonly TransformedColl ection<K, V>.Transformer Function;
public readonly IComparer<V> ValueComparer;
public FunctionDiction ary(
ICollection<K> keys,
TransformedColl ection<K, V>.Transformer function,
IComparer<V> valueComparer)
{
this.Keys = keys;
this.Function = function;
this.ValueCompa rer = valueComparer == null ? Comparer<V>.Def ault
: valueComparer;
}
public bool ContainsKey(K key) { return Keys.Contains(k ey); }
public void Add(K key, V value) { throw Immutable.Make( this); }
public bool Remove(K key) { throw Immutable.Make( this); }
public bool TryGetValue(K key, out V v)
{
bool found = Keys.Contains(k ey);
if (found)
v = Function(key);
else
v = default(V);
return found;
}
ICollection<K> IDictionary<K, V>.Keys { get { return Keys; } }
public ICollection<V> Values { get { return new
TransformedColl ection<K, V>(Keys, Function); } }
public V this[K key]
{
get
{
if (Keys.Contains( key))
return Function(key);
else
throw new KeyNotFoundExce ption(string.Fo rmat("{0} not in
{1}", key, this));
}
set { throw Immutable.Make( this); }
}
public void Add(KeyValuePai r<K, V> kvp) { throw Immutable.Make( this); }
public void Clear() { throw Immutable.Make( this); }
public bool Contains(KeyVal uePair<K, V> kvp) { return
Keys.Contains(k vp.Key) && ValueComparer.C ompare(Function (kvp.Key),
kvp.Value) == 0; }
public void CopyTo(KeyValue Pair<K, V>[] kvps, int index)
{
foreach (K key in Keys)
kvps[index++] = new KeyValuePair<K, V>(key, Function(key));
}
public bool Remove(KeyValue Pair<K, V> kvp) { throw
Immutable.Make( this); }
public int Count { get { return Keys.Count; } }
public bool IsReadOnly { get { return true; } }
public IEnumerator<Key ValuePair<K, V>> GetEnumerator()
{
foreach (K key in Keys)
yield return new KeyValuePair<K, V>(key, Function(key));
}
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
public class AddKeyValuePair <K, V> : IDictionary<K, V>
{
public readonly IDictionary<K, V> Parent;
public readonly K Key;
public V Value;
public readonly IEqualityCompar er<K> KeyComparer;
public readonly IEqualityCompar er<V> ValueComparer;
public AddKeyValuePair (IDictionary<K, V> parent, K key, V value,
IEqualityCompar er<K> keyComparer, IEqualityCompar er<V> valueComparer)
{
if (parent.Contain sKey(key))
throw new ArgumentExcepti on("parent contains key");
this.Parent = parent;
this.Key = key;
this.Value = value;
this.KeyCompare r = keyComparer == null ?
EqualityCompare r<K>.Default : keyComparer;
this.ValueCompa rer = valueComparer == null ?
EqualityCompare r<V>.Default : valueComparer;
}
public bool ContainsKey(K k) { return KeyComparer.Equ als(k, Key) ||
Parent.Contains Key(k); }
public void Add(K k, V v)
{
if (KeyComparer.Eq uals(k, Key))
throw new ArgumentExcepti on(string.Forma t("{0} already
contains {1}", this, k));
else
Parent.Add(k, v);
}
public bool Remove(K k)
{
if (KeyComparer.Eq uals(k, Key))
throw Immutable.Make( this, string.Format(" Cannot remove key:
{0}", k));
else
return Parent.Remove(k );
}
public bool TryGetValue(K k, out V v)
{
if ( KeyComparer.Equ als(k, Key) )
{
v = Value;
return true;
}
else
return Parent.TryGetVa lue(k, out v);
}
public V this[K k]
{
get
{
if ( KeyComparer.Equ als(k, Key) )
return Value;
else
return Parent[k];
}
set {
if (KeyComparer.Eq uals(k, Key))
Value = value;
else
Parent[k] = value;
}
}
public ICollection<K> Keys { get { return new
AddItem<K>(Pare nt.Keys, Key, KeyComparer); } }
public ICollection<V> Values { get { return new
AddItem<V>(Pare nt.Values, Value, ValueComparer); } }
public void Clear() { throw Immutable.Make( this,
string.Format(" Cannot clear {0}", this)); }
public void Add(KeyValuePai r<K, V> kvp)
{
if (KeyComparer.Eq uals(kvp.Key, Key))
throw new ArgumentExcepti on(string.Forma t("{0} already
contains {1}", this, kvp.Key));
else
Parent.Add(kvp) ;
}
public bool Contains(KeyVal uePair<K, V> kvp)
{
V v;
return TryGetValue(kvp .Key, out v) &&
ValueComparer.E quals(kvp.Value , v);
}
public void CopyTo(KeyValue Pair<K, V>[] kvps, int index)
{
kvps[index++] = new KeyValuePair<K, V>(Key, Value);
Parent.CopyTo(k vps, index + 1);
}
public bool Remove(KeyValue Pair<K, V> kvp)
{
if (KeyComparer.Eq uals(kvp.Key, Key))
throw Immutable.Make( this, string.Format(" Cannot remove key:
{0}", kvp.Key));
else
return Parent.Remove(k vp);
}
public int Count { get { return Parent.Count + 1; } }
public bool IsReadOnly { get { return Parent.IsReadOn ly; } }
public IEnumerator<Key ValuePair<K, V>> GetEnumerator()
{
yield return new KeyValuePair<K, V>(Key, Value);
foreach (KeyValuePair<K , V> kvp in Parent)
yield return kvp;
}
System.Collecti ons.IEnumerator
System.Collecti ons.IEnumerable .GetEnumerator( ) { return GetEnumerator() ; }
}
#endregion
--
Helge Jensen
mailto:he****** ****@slog.dk
sip:he********* *@slog.dk
-=> Sebastian cover-music:
http://ungdomshus.nu <=-