如何在通用方法中允许派生的集合

时间:2019-07-05 09:36:17

标签: c# collections casting covariance

我有多个表示对象的类,这些对象都具有由Unity Rect字段描述的范围。 (Zone, Room, Structure, Tunnel, Room ...)

这些对象通常放置在集合中。 (List<Zone>, List<Room> ...)

我希望有一个静态实用工具方法,该方法将测试其中一个是否与此类对象集合中的任何边界重叠,而不必使用LINQ强制转换List。

public static bool BoundsOverlapsOtherBounds(Bounds bound, List<Bounds>)

我应该如何使用C#多态性,接口,协方差来实现此目的,而无需首先将List<Room>List<Zone>强制转换为List<Bounds>

到目前为止,我的尝试始终会产生“ 无法将X转换为Y” 编译器错误。

2 个答案:

答案 0 :(得分:1)

由于(暗含的)所有这些类型已经从Bounds继承,因此您无需将List<Room>List<Zone>强制转换为List<Bounds>

您可以这样做:

bool BoundsOverlapsOtherBounds<T>(Bounds bound, List<T> bounds) where T : Bounds

通用约束意味着只要List<T>实现或继承T,就可以将任何Bounds传递给方法。

因此,如果您有一个List<Room>,则可以将其传递给方法而无需显式转换它:

var rooms = new List<Room>();
var otherBounds = new Bounds();
var overlaps = BoundsOverlapsOtherBounds(otherBounds, rooms);

您甚至不必指定通用参数,因为可以推断出它。


如果这些对象不共享相同的类型,那么很可能应该这样做。继承是 a 解决方案,但是我们不需要使用它来使类型具有共同的特征。有时这使我们陷入困境。接口也可能有意义:

interface IHasBoundaries // not a great name?
{
    Boundaries Bounds { get; }
}

那是多态性。 多种形式(或类型)可以实现该接口,并且您根本不在乎是什么使它们与众不同-仅仅是它们的共同点。您可以编写处理IHasBoundaries的代码,在这种情况下,您唯一需要了解的对象就是它们实现了接口。

然后您的方法如下:

bool BoundsOverlapsOtherBounds<T>(IHasBoundaries bound, List<T> bounds) 
    where T : IHasBoundaries

答案 1 :(得分:0)

问题在于List<Zone>List<Bounds>不同。您可以在Room上添加List<Bounds>,但不能在List<Zone>上添加IEnumerable,这就是它们不能转换的原因。但是,我假设您只想迭代边界列表,而不更改集合,为此,您只需要一个List而不是一个IEnumerable<Zone>。由于IEnumerable<Bounds>的功能与bounds相同,因此允许这样做。因此,如果您确实只想读取public static bool BoundsOverlapsOtherBounds(Bounds bound, IEnumerable<Bounds> bounds)参数的元素,请将签名更改为:

List

应接受(Zone, Room, …)中的任何Partial

希望这会有所帮助