Hi there,
Suppose I have the following class:
public class CacheItem<T>
{
public T Data
{
get { ... }
}
public bool IsExpired
{
get { ... }
}
//other properties
}
How would I go about iterating over a collection of cache items where T could be different for each cache item In other words, how do I get this to work:
foreach (CacheItem< > cacheItem in Cache.Items)
{
if (cacheItem.IsExpired) { ... }
}
As far as I can tell, this is impossible. The best I could do would be to define a non-generic ICacheItem interface and code against that. Then I could provide the generic CacheItem<T> class as a useful implementation of ICacheItem.
Does anyone have further insight into this problem
Thanks,
Kent

Generics Question
vembloud
[Edit]: After posting I realized this is exactly what John.Doe is refering too...
If each item in your collection that you're enumerating from all derive from a specific base class you can use that base class in your foreach statement.
For your example lets suppose we have an interface IExpirable such that:
public
interface IExpirable{
bool IsExpired { get;}
}
And all of your cache items in your cache implement this interface you can use the following foreach loop:
foreach
(CacheItem<IExpirable> cacheItem in Cache.Items){
if(cacheItem.IsExpired)...
}
I hope this helps.
HongZ
Generics could be your solution here, but the point is that your class is not generic. Try this (the generic T replaces your non-generic class):
public
interface IExpirable{
bool IsExpired { get; }
} public class Cache<T> where T : IExpirable
{
public void ClearCache()
{
foreach (T cacheItem in Items)
{
if (cacheItem.IsExpired) { }
}
}
public T[] Items
{
get { return null; }
}
}
HTH!!!
KaraokeJoe
Thanks, but that does not help. All the items in the stack are of the same type (ie. they have the same T). In my case, I'm trying to iterate over CacheItem< >, not CacheItem<T>.
Kent
JesperWelander
JB Metrics
Well, just because I was curious, I tried a few things, but all, maybe your attempts, too, to cast a strong type to a "partially known" type defeat the purpose of generics to define strong types and avoid casting. I just tried to figure out if the elements of the list are of the same abstract generic type and call the known method on them if so:
class Program{
static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(new TG1());
list.Add(new TG2());
foreach (object obj in list)
{
Type type = obj.GetType();
Type genericType = obj.GetType().BaseType.GetGenericTypeDefinition();
if (genericType == typeof(TG<>))
{
PropertyInfo isExpiredProperty = type.GetProperty("IsExpired");
Console.WriteLine(isExpiredProperty.GetValue(obj, null));
}
}
}
} public class TG<T> where T : class
{
private bool isExpired = false;
public bool IsExpired
{
get { return this.isExpired; }
set { this.isExpired = value; }
}
} public class T1 {} public class T2 {} public class TG1 : TG<T1> {} public class TG2 : TG<T2>{}
This works, but using an interface will be significantly faster during runtime, because you do not have to go through reflection.
I think what you would need is called a variance cast, so e.g. casting TG<T1> to TG<object> as a supertype which does not really exist, but afaik none of the popular programming languages supports that yet.
Arun-MS
Uh, no offense, but did you even read the thread What you mentioned here was suggested similar several times, even by the original poster in the very first post:
"The best I could do would be to define a non-generic ICacheItem interface and code against that. Then I could provide the generic CacheItem<T> class as a useful implementation of ICacheItem."
mihkeltt
Not exactly the solution but the answer may be through reflection.
I'll look into it tomorrow at night, after work, if, in the meanwhile, no one posts the answer.
AMP
Hi,
I unmarked the above as the answer because I can't see how it helps me implement the following:
foreach (CacheItem< > cacheItem in Cache.Items)
{
if (cacheItem.IsExpired) { ... }
}
If someone could point out how I would implement that loop I'd be extremely grateful.
Thanks,
Kent
ZAP2944
check this article: http://msdn2.microsoft.com/en-US/library/ee5kxzk0.aspx
See if it helps.
edmund83
Thanks. That is the approach I mentioned in my original post, and is the only way I could get it to work.
What I was wondering was whether there was way to tell the compiler that I didn't know the exact type for T, but I wasn't going to access any members of the cache items that "relied on" knowing T. I'm not sure on the definition of "relied on" here.
I guess I was just hoping to avoid the extra interface because it clutters my API. Also, this would be a problem for existing types that haven't defined a corresponding non-generic interface. For example:
List<Nullable< >> nullables = ...;
foreach (Nullable< > nullable in nullables)
{
if (nullable.HasValue) { ... }
}
What we're saying is that this just won't work, and there is no way around it but to provide the exact type of nullables in use.
Thanks for all the input - keep it coming if you have more.
Kent