Reputation: 15619
Could someone please explain to me why the following cast does not work and the solution to the problem.
I have a GroupedResult
:
public class GroupedResult<TKey, TElement>
{
public TKey Key { get; set; }
private readonly IEnumerable<TElement> source;
public GroupedResult(TKey key, IEnumerable<TElement> source)
{
this.source = source;
this.Key = key;
}
}
public class Bacon
{
}
I would like to cast the List<string, Bacon>
to List<string, object>
. I have tried the following and other ways.
var list = new List<GroupedResult<string, Bacon>>
{
new GroupedResult<string, Bacon>("1", new List<Bacon>()),
new GroupedResult<string, Bacon>("2", new List<Bacon>())
};
var result = list.Cast<GroupedResult<string, object>>().ToList();
But I always get the following error:
InvalidCastException: Unable to cast object of type 'GroupedResult
2[System.String,UserQuery+Bacon]' to type 'GroupedResult
2[System.String,System.Object]'.
Upvotes: 1
Views: 1634
Reputation: 32296
For that to work you'd have to use an interface instead of class type.
public interface IGroupResult<TKey, out TElement>
{
TKey Key { get; set; }
}
public class GroupedResult<TKey, TElement> : IGroupResult<TKey, TElement>
{
public TKey Key { get; set; }
private readonly IEnumerable<TElement> source;
public GroupedResult(TKey key, IEnumerable<TElement> source)
{
this.source = source;
this.Key = key;
}
}
public class Bacon
{
}
Then you could do something like
IGroupResult<string, Bacon> g = new GroupedResult<string, Bacon>("1", new List<Bacon>());
var result = (IGroupResult<string, object>)g;
That's because co-variance is only allowed on interfaces and delegates, but not classes. Note that you should only mark a type as co-variant if it only comes out of the interface (method return type and read only properties).
Though you should ask yourself why you want to cast something to object
when you're working with generics. The main point of generics is to avoid having to use the object
type as a catch all and this could indicate a flaw in your design that you might want to rethink.
Upvotes: 1
Reputation: 15015
You can have a Cast
method in your GroupedResult
class and use it to do the casting!
public class GroupedResult<TKey, TElement>
{
public TKey Key { get; set; }
private readonly IEnumerable<TElement> source;
public GroupedResult(TKey key, IEnumerable<TElement> source)
{
this.source = source;
this.Key = key;
}
public GroupedResult<TKey, object> Cast()
{
return new GroupedResult<TKey, object>(Key, source.Cast<object>());
}
}
public class Bacon
{
}
static void Main(string[] args)
{
var list = new List<GroupedResult<string, Bacon>>
{
new GroupedResult<string, Bacon>("1", new List<Bacon>()),
new GroupedResult<string, Bacon>("2", new List<Bacon>())
};
// var result = list.Cast<GroupedResult<string, object>>().ToList();
List<GroupedResult<string,object>> result = list.Select(B => B.Cast()).ToList();
}
Upvotes: 0
Reputation: 34180
why aren'y you using GroupedResult<string, object>
instead of GroupedResult<string, Bacon>
? like this:
var list = new List<GroupedResult<string, object>>
{
new GroupedResult<string, object>("1", new List<Bacon>()),
new GroupedResult<string, object>("2", new List<Bacon>())
};
Upvotes: 0
Reputation: 2254
It would be better to start with a GroupedResult < string, object> then you COULD do this
new GroupedResult<string, object>("2", new List<Bacon>())
Upvotes: 0