是否可以强制转换 C# 泛型参数

本文关键字:泛型 参数 转换 是否 | 更新日期: 2023-09-27 18:34:54

我用签名编写了一个方法:

private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems)

我尝试以以下方式调用它:

ConvertToClientItems(approvedSellers);

其中approvedSellers属于 BaseCollection<Seller> 型 - Seller是我无法控制的类。

这不应该吗?Visual Studio向我抛出了一个错误,说它无法将BaseCollection<seller>转换为BaseCollection<object>

是否可以强制转换 C# 泛型参数

好吧,想象一下如下所示的代码:

private List<ClientItem> ConvertToClientItems(BaseCollection<object> serverItems) {
    serverItems.Add(new Buyer());
}

这应该编译,因为Buyer是一个object

但是,如果您传递BaseCollection<Seller>,您只是尝试将买家添加到卖家列表中。

因此,声明

BaseCollection<Seller>BaseCollection<object>的一个亚型

仅当BaseCollection确保泛型类型 T 仅用于输出位置时,才成立。上面的添加示例将在输入位置使用T


要解决此问题,您有以下选择:

  • 通过添加 out 关键字使 BaseCollection 成为"协变",这将需要删除任何Add方法。但是,这可能会使您的收藏变得毫无用处。
  • 将协变接口传递给方法。如果你只需要读取serverItems,传递一个IEnumerable,它已经是协变的(你在注释中提到 BaseCollection 已经实现了 IEnumerable(:

    private List<ClientItem> ConvertToClientItems(IEnumerable<object> serverItems) {
        // You can only read serverItems here, so we are fine.
    }
    
  • 使方法本身泛型

    private List<ClientItem> ConvertToClientItems<T>(BaseCollection<T> serverItems) {
        // This also prevents the evil `Add` call, since you'd need to create
        // an object of the correct type T first.
    }
    

在 BaseCollection 中,您必须使用 "out" 关键字使 T 协变。

更多信息 http://msdn.microsoft.com/en-us/library/dd233059.aspx。

(IEnumerable 有效,因为它是协变的。

public interface BaseCollection<out T>