强制转换和泛型约束

本文关键字:泛型 约束 转换 | 更新日期: 2023-09-27 18:22:23

我有这个事件类:

sealed class AnEvent : EventArgs
{
    IEnumerable<ItemWrapper<AnAbstractClass>> Items { get; set; }
}

这是这样用的:

class ItemsProcessor 
{
    delegate void OnItemsProcessedHandler(object sender, AnEvent e);
    event OnItemsProcessedHandler OnItemsProcessed;
    //...
}

我使用这个包装类:

sealed class ItemWrapper<T>
            where T: AnAbstractClass 
{
    T Item { get; set; }
    Metadata Metadata { get; set; }
    ItemWrapper(T item, Metadata metadata) 
    {
        Item = item;
        Metadata = metadata;
    }
}

我在ItemsProcessor课上有这个方法:

internal void DoSomethingWithList<T>(IEnumerable<T> items) 
            where T: AnAbstractClass, new()
{
    IEnumerable<ItemWrapper<T>> processedItems = WrapItems<T>(items);
    OnItemsProcessed(this, new AnEvent() { Items = processedItems }); //error here
}

问题出在此代码示例的最后一行;当我尝试使用本地IEnumerable设置属性Items AnEvent 时。编译器拒绝继续告诉我它不能隐式地将IEnumerable<ItemWrapper<T>>转换为IEnumerable<ItemWrapper<AnAbstractClass>>。我认为应该没问题,因为我为此方法添加了约束where T: AnAbstractClass, new(),但即使显式强制转换(使用带括号的经典强制转换或使用Convert<>(,我也得到了一个InvalidCastException

我目前对方法DoSomethingWithList的解决方法是:

var temp = processedItems.Select(x =>
    {
        return new ItemWrapper<AnAbstractClass>(x.Item, x.Metadata);
    });
OnItemsProcessed(this, new AnEvent() { Items = temp });

所以它现在工作正常,但我想知道为什么如果不使用这个必须迭代列表中所有项目的LINQ转换,它就不能工作?对我来说很明显,您应该能够毫无错误地转换它,因为我添加了约束即使使用显式强制转换以使编译器接受我的代码,也会引发异常......任何人都可以指出我这里出了什么问题?

abstract class AnAbstractClass 
{
}
class ItemClass : AnAbstractClass
{
}

如果您想尝试,可以轻松复制粘贴的WrapItems快速实现:

IEnumerable<ItemWrapper<T>> WrapItems<T>(IEnumerable<T> items)
        where T : AnAbstractClass, new()
{
    List<ItemWrapper<T>> ret = new List<ItemWrapper<T>>();
    foreach (var item in items)
    {
        ret.Add(new ItemWrapper<T>(item, new Metadata()));
    }
    return ret;
}

强制转换和泛型约束

如果将ItemWrapper更改为

sealed class ItemWrapper
{
    AnAbstractClass Item { get; set; }
    Metadata Metadata { get; set; }
    ItemWrapper(AnAbstractClass item, Metadata metadata) 
    {
        Item = item;
        Metadata = metadata;
    }
}

你失去了什么?