I'm working on developing a framework and I'm encountering issues with trying to upcast to a generic type. I suspect that what I'm dealing with relates to covariance and contravariance, but I'm not quite sure how to navigate it. Here is my code snippet where I'm getting the exception "object must implement iconvertible generic type":
```csharp
public static async Task<T> GetTypedListItemByIdAsync<T>(this IListItemCollection listItemCollection, int id, params System.Linq.Expressions.Expression<Func<IListItem, object>>[] selectors) where T : TypedListItem
{
var item = await listItemCollection.GetByIdAsync(id, selectors);
return (T)Convert.ChangeType(new TypedListItem(item), typeof(T));
}
```
I've also tried using dynamic types to bypass this, but it still results in an error:
```csharp
public static async Task<out T> GetTypedListItemByIdAsync<T>(this IListItemCollection listItemCollection, int id, params System.Linq.Expressions.Expression<Func<IListItem, object>>[] selectors) where T : TypedListItem
{
var item = await listItemCollection.GetByIdAsync(id, selectors);
dynamic typedListItem = new TypedListItem(item);
return typedListItem;
}
}
```
2 Answers
I see where you're coming from! If you sometimes know the type of `T`, you might think about creating factory methods that handle each type to make it more convenient for users of your framework. While that could mean writing a few extra lines of code, it would help maintain type safety without losing flexibility. If you absolutely cannot know what `T` is, your approach of forcing the developers to handle their casting could be the way to go.
Your issue seems to be related to the casting process. Just to clarify, what you're attempting could be a bit confusing since you're trying to downcast, not really upcast. You’re trying to convert a base type (`TypedListItem`) into a subclass (`T`) which doesn’t work unless you actually have an instance of `T`. The `TypedListItem` object you create isn't intrinsically an instance of `T`, so you can’t just cast it like that. You might want to look into using `Activator.CreateInstance(typeof(T))` to create an instance of `T` if your framework design allows it, or you can consider using reflection, but keep in mind that might come with performance trade-offs!
Thanks for the insight! I really thought I could just handle it generically. I guess I’ll have to look into those workarounds but I’m a bit wary of the performance impact.
Great point! I might just do that, keeping the generic parts where possible while providing some clear examples for the common cases.