You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将List<派生类>转为List<基类>且不破坏引用?

解决方案

方案1:改用协变接口类型直接赋值

List<T>本身不支持协变,但IList<T>、ICollection<T>这类接口支持引用类型的协变。把currentItemBasesList的定义改成IList<ItemBase>,就能直接把子类列表赋值给它,此时两个变量指向同一个底层列表,所有增删改操作都会同步:

// 修改字段定义
public IList<ItemBase> currentItemBasesList;

// 赋值时直接引用原列表
currentItemBasesList = chestplateBasesList;

注意:这种方式下,不能通过currentItemBasesList添加非ArmorBase类型的ItemBase子类(比如WeaponBase),否则会抛出类型转换异常——因为底层列表本质是List<ArmorBase>,只能容纳ArmorBase实例。

方案2:编写列表包装类代理操作

如果必须保持currentItemBasesList为List<ItemBase>类型,或者需要更灵活的类型校验,可以写一个包装类,把对ItemBase列表的操作转发到底层的子类列表上。示例代码如下:

public class CovariantListWrapper<TBase, TDerived> : List<TBase> where TDerived : TBase
{
    private readonly List<TDerived> _sourceList;

    public CovariantListWrapper(List<TDerived> sourceList)
    {
        _sourceList = sourceList;
    }

    // 重写核心操作方法,转发到源列表
    public new void Add(TBase item)
    {
        if (item is TDerived derivedItem)
            _sourceList.Add(derivedItem);
        else
            throw new ArgumentException($"只能添加{typeof(TDerived).Name}类型的项");
    }

    public new bool Remove(TBase item)
    {
        return item is TDerived derivedItem && _sourceList.Remove(derivedItem);
    }

    public new int Count => _sourceList.Count;

    public new TBase this[int index]
    {
        get => _sourceList[index];
        set
        {
            if (value is TDerived derivedItem)
                _sourceList[index] = derivedItem;
            else
                throw new ArgumentException($"只能设置{typeof(TDerived).Name}类型的项");
        }
    }

    // 根据需求补充实现Clear、Insert、RemoveAt等其他方法
}

使用时直接创建包装类实例赋值:

currentItemBasesList = new CovariantListWrapper<ItemBase, ArmorBase>(chestplateBasesList);

这样对currentItemBasesList的所有操作都会同步到chestplateBasesList,同时保留currentItemBasesList的List<ItemBase>类型。

方案3:标记当前选中列表,直接操作源列表

如果不需要currentItemBasesList作为统一操作入口,也可以用一个标记变量记录当前选中的列表类型,操作时直接对对应源列表执行操作:

// 定义枚举标记当前选中的列表类型
public enum SelectedItemCategory
{
    Helmet, Chestplate, ShoulderGuards, Armguards, Thighguards, Boots, Shield, Cape, Weapon
}

public SelectedItemCategory currentSelectedCategory;

// 示例:移除选中列表中的项
public void RemoveItemFromSelectedList(ItemBase item)
{
    switch(currentSelectedCategory)
    {
        case SelectedItemCategory.Chestplate:
            chestplateBasesList.Remove(item as ArmorBase);
            break;
        case SelectedItemCategory.Weapon:
            weaponBasesList.Remove(item as WeaponBase);
            break;
        // 补充其他分支
    }
}

这种方式完全绕开了列表引用的问题,直接操作源列表,但需要额外逻辑来区分当前操作的目标列表。

内容的提问来源于stack exchange,提问作者Bruno Pasini Fiorini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:15:59