Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Casting generic collection containing interface.

Posted on 2010-09-03
10
Medium Priority
?
578 Views
Last Modified: 2012-08-13
I have some objects that are cacheable.  The interface looks like this:

public interface ICacheable {
    string EntityTag { get; }
}

One of the classes that implement it look like this:

public class User : ICacheable {
     public int Id { get; }
     public int Version { get; }

     public string EntityTag { get { return String.Format("{0}-{1}", Id, Version); } }
}

Now, I have a method that returns a readonly collection of users (System.Collections.ObjectModel.ReadOnlyCollection<User>) and I need to pass this to a method that only accepts a readonly collection of ICacheable objects.  I would think that the compiler would handle this kind of cast, but it isn't working.

It boils down to why won't this work:

public System.Collections.ObjectModel.ReadOnlyCollection<ICacheable> GetUsers() {
   ReadOnlyCollection<Users> userList = DataManager.GetUsers();

   return userList;
}
0
Comment
Question by:ChetOS82
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
10 Comments
 
LVL 8

Expert Comment

by:Gururaj Badam
ID: 33597933
When you say it isn't working what exactly is happening?
0
 
LVL 18

Author Comment

by:ChetOS82
ID: 33597949
Error: Cannot implicitly convert type ReadOnlyCollection<User> to ReadOnlyCollection<ICacheable>.

If I try to explictly cast, I get the same error without the word "implicitly".
0
 
LVL 8

Expert Comment

by:Gururaj Badam
ID: 33598050
public System.Collections.ObjectModel.ReadOnlyCollection<ICacheable> GetUsers() {
   ReadOnlyCollection<ICloneable> userList = DataManager.GetUsers();

   return userList;
}

Observe the userList declaration
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 18

Author Comment

by:ChetOS82
ID: 33598082
Not sure what you are getting at.  1) DataManager.GetUsers returns a ReadonlyCollection<User>, 2) User is not ICloneable (if I use ICacheable instead, I still get invalid cast error).
0
 
LVL 16

Accepted Solution

by:
kris_per earned 1800 total points
ID: 33598093

Try the Cast method of ReadOnlyCollection/IEnumerable for this (with LINQ)

ReadOnlyCollection<User> users;

IEnumerable<ICacheable> clist = users.Cast<ICacheable>();
0
 
LVL 8

Expert Comment

by:Gururaj Badam
ID: 33598096
Since you're a base type (interface) it's good to replace all references with ICloneable include your GetUsers unless it's not your code.
0
 
LVL 18

Author Comment

by:ChetOS82
ID: 33598141
When you say ICloneable, do you mean ICacheable?  I cannot replace the return of DataManager.GetUsers() because other code in the system doesn't care that the User object is ICacheable.

@kris_per: Is that essentially the same as this:
List<ICacheable> cacheableUsers = new List<ICacheable>();
foreach (ICacheable user in userList) {
     cacheableUsers.Add(user);
}
return new ReadOnlyCollection<ICacheable>(cacheableUsers);

That was what I used as a workaround.  I was hoping that C# could handle the cast implicily.  If not, I'll replace this code with the Cast call you recommended.
0
 
LVL 8

Assisted Solution

by:Gururaj Badam
Gururaj Badam earned 200 total points
ID: 33598177
The problem you're seeing is CoVariance/ContraVariance. This has been addressed in 4.0.
0
 
LVL 18

Author Comment

by:ChetOS82
ID: 33598284
I realize that this is an issue of covariance, but I was hoping that someone knew if I was just looking at this wrong.  Apparently covariance is supported everywhere except with Generics.  So, in C# 4 I will be able to do this implicitly.

Some points to Novice for giving the problem a name, most points to kris_per for validation.

I ended up writting a method that can be replaced later.  I prefer it over the Linq Cast<> for two reasons.  1) I don't have Linq referenced in this project, 2) Cast returns an IEnumerable, but I want a ReadOnlyCollection.

public ObjectModel.ReadOnlyCollection<ICacheable> MakeCollectionCacheable<T>(ObjectModel.ReadOnlyCollection<T> list) {
   var cacheableList = new List<ICacheable>(list.Count);
   foreach (ICacheable cacheableObject in list) {
       cacheableList.Add(cacheableObject);
   }
   return new ObjectModel.ReadOnlyCollection<ICacheable>(cacheableList);
}
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question