ChetOS82
asked on
Casting generic collection containing interface.
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.Object Model.Read OnlyCollec tion<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.ObjectM odel.ReadO nlyCollect ion<ICache able> GetUsers() {
ReadOnlyCollection<Users> userList = DataManager.GetUsers();
return userList;
}
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.Object
It boils down to why won't this work:
public System.Collections.ObjectM
ReadOnlyCollection<Users> userList = DataManager.GetUsers();
return userList;
}
When you say it isn't working what exactly is happening?
ASKER
Error: Cannot implicitly convert type ReadOnlyCollection<User> to ReadOnlyCollection<ICachea ble>.
If I try to explictly cast, I get the same error without the word "implicitly".
If I try to explictly cast, I get the same error without the word "implicitly".
public System.Collections.ObjectM odel.ReadO nlyCollect ion<ICache able> GetUsers() {
ReadOnlyCollection<IClonea ble> userList = DataManager.GetUsers();
return userList;
}
Observe the userList declaration
ReadOnlyCollection<IClonea
return userList;
}
Observe the userList declaration
ASKER
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).
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
ASKER
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<ICachea ble>(cache ableUsers) ;
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.
@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<ICachea
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.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.ReadOnlyCollec tion<ICach eable> MakeCollectionCacheable<T> (ObjectMod el.ReadOnl yCollectio n<T> list) {
var cacheableList = new List<ICacheable>(list.Coun t);
foreach (ICacheable cacheableObject in list) {
cacheableList.Add(cacheabl eObject);
}
return new ObjectModel.ReadOnlyCollec tion<ICach eable>(cac heableList );
}
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.ReadOnlyCollec
var cacheableList = new List<ICacheable>(list.Coun
foreach (ICacheable cacheableObject in list) {
cacheableList.Add(cacheabl
}
return new ObjectModel.ReadOnlyCollec
}