Christopher Edwards
Christopher Edwards

Reputation: 6659

Cast from base generic type to derived generic type where the derived type has additional type constraints

Actually whilst casting would be the ideal even "newing up" the derived type would work in my specific scenario. I suspect this isn't possible when I don't have access to the concrete type of the generic parameter.

public class OrderableCollection<T> : Collection<T> where T : IOrderable, new()
{
...
}

public class ArchivableOrderableCollection<T> : OrderableCollection<T> where T : IOrderable, IArchivable, new()
{
...
}

public class OrderableListDisplay<TItem> where TItem : IOrderable, new()
{
    protected OrderableCollection<TItem> orderableItems { get; set; }

    protected virtual async Task RestoreItem(TItem item)
    {
        if (item is not IArchivable)
        {
            throw new ArgumentException();
        }

        // None of these compile
        var aoc1 = orderableItems as ArchivableOrderableCollection<TItem>;
        var aoc2 = new ArchivableOrderableCollection<TItem>(orderableItems);
        var aoc3 = (ArchivableOrderableCollection<TItem>)(object)(OrderableItems);

        // I think I need something like
        var aoc4 = orderableItems as ArchivableOrderableCollection<TItem> where TItem : IArchivable
    }  
}

Upvotes: 0

Views: 292

Answers (1)

Moho
Moho

Reputation: 16553

You could add a generic argument w/ constraints to your RestoreItem method

protected virtual async Task RestoreItem<T>(T item)
    where T : TItem, IArchivable
{
    if( orderableItems is not ArchivableOrderableCollection<T> items )
    {
        throw new InvalidOperationException();
    }

    // do what you need to here
    items.Restore( item );
}

However, I think you should reconsider your design. Implement base and derived classes for OrderableListDisplay<T> so that a derived version may constrain the TItem to IArchivable properly and expects and implementation of ArchivableOrderableCollection<T>:

public class OrderableListDisplay<TItem>
    where TItem : IOrderable, new()
{
    private readonly OrderableCollection<TItem> _items = null;

    public OrderableListDisplay( OrderableCollection<TItem> items )
    {
        _items = items ?? throw new ArgumentNullException( nameof( items ) );
    }
}

public class ArchivableOrderableListDisplay<TItem>
    : OrderableListDisplay<TItem>
    where TItem : IArchivable
{
    private readonly ArchivableOrderableCollection<TItem> _items = null;

    public ArchivableOrderableListDisplay( ArchivableOrderableCollection<TItem> items )
        : base( items )
    {
        _items = items;
    }

    protected async Task RestoreItem( TItem item )
    {
        _items.Restore( item );
    }
}

Upvotes: 1

Related Questions