C#不能使用**作为**来将基类转换为派生类

时间:2013-05-20 07:56:02

标签: c# generics casting

class Building {
}

class Home: Building {
}

private List<Building>   buildings;
public T[] FindBuildings<T>() {       
    return buildings.FindAll(x => x is T).ToArray() as T[];
}

我有一个列表可以保存地图上的所有建筑物,并编写一个功能来查找特定的建筑类型。 我希望使用FindBuildings<Home>()来获取包含地图上所有住宅建筑的数组,但是当我运行代码时,我发现函数总是返回null,似乎as不起作用。这是否意味着as无法使用泛型类型参数?

所以,我改变了代码:

private List<Building>   buildings;
public Building[] FindBuildings<T>() {       
    return buildings.FindAll(x => x is T).ToArray();
}

使用FindBuildings<Home>() as Home[]访问地图上的住宅楼宇。但是......它仍然是空的。

我看到了一个Unity3d的例子,告诉我使用'as'转换数组类型,为什么我失败了?

using UnityEngine;
using System.Collections;

public class example : MonoBehaviour {
    void OnMouseDown() {
        HingeJoint[] hinges = FindObjectsOfType(typeof(HingeJoint)) as HingeJoint[];
        foreach (HingeJoint hinge in hinges) {
            hinge.useSpring = false;
        }
    }
}

2 个答案:

答案 0 :(得分:10)

你需要这样做:

return buildings.OfType<T>.ToArray();

解释为什么你的尝试不起作用。

表达式buildings.FindAll(x => x is T)的类型为List<Building>。这是因为buildings本身是List<Building>FindAll并没有神奇地改变返回值中项目的类型。因此,ToArray()生成Building[]

as运算符仅在直接转换有效的情况下返回非空值。由于Building[]Home[]的广告无效,as始终会生成null。不要因将Home[]转换为Building[]这一事实而感到困惑。

答案 1 :(得分:7)

问题是Building[]不是Home[]。所以这段代码:

public T[] FindBuildings<T>() {       
    return buildings.FindAll(x => x is T).ToArray() as T[];
}

...始终尝试将Building[]视为T[],并在T[]既不是T也不Building时返回Object }。您需要创建T[]才能开始。幸运的是,LINQ实际上让你很容易:

public T[] FindBuildings<T>() {       
    return buildings.OfType<T>().ToArray();
}

重要的是,OfType<T>会返回IEnumerable<T> - 而您对List<Building>.FindAll的回复仍然会返回List<Building>,因此ToArray正在创建{ {1}}。

顺便说一句,我建议使用强制转换代替Building[],除非{em} as返回null。如果您希望转换失败为错误条件,则直接转换表示通过异常立即,而不是稍后获得as,掩盖原始问题。