我有一个抽象类:
abstract class A {
// some stuff
float val = 0;
abstract float Foo();
}
class B1 : A {
override float Foo() {
Console.WriteLine("B1: " + val);
}
}
class B2 : A {
override float Foo() {
Console.WriteLine("B2: " + val);
}
}
我有一个List<A> a
,我想得到给定类型T的第一项:
public T GetTypeFromList<T>() {
foreach (var item in a) {
T tmp = item as T; // doesn't compile
if (tmp != null)
return tmp;
}
throw new Exception("Type isn't in list.");
}
有办法吗?
编辑:
它显示:类型参数“ T”不能与“ as”运算符一起使用
因为它没有类类型约束也没有“类”
约束
答案 0 :(得分:4)
答案 1 :(得分:3)
一种方法是使用LINQ .First
方法。您可以修改每个元素的类型,然后返回类型为T
的第一个元素。如果找不到元素,.First
会引发异常:
List<A> myList;
var obj = (MyTargetType)myList.First(e => e is MyTargetType);
顺便说一句:reference and nullable types只能使用运算符as
。
答案 2 :(得分:2)
要使代码正常工作,您必须在方法中添加where
约束:
static T GetTypeFromList<T>(List<A> a) where T: class
,然后它将起作用。
因为,当您使用as
关键字时,它将对象转换为给定的 引用或可空值类型 。如果转换失败,则as
运算符的结果将为null
。 null
仅对可为空的类型有效。为了使编译器满意,您必须在方法签名中添加class
约束。
但是 ,为此,System.Linq
命名空间中已经有内置方法出口。它称为OfType<>
。它根据指定的类型过滤IEnumerable
的元素。
var b2s = list.OfType<B2>();
要获得第一项,可以使用First()
或FirstOrDefault()
,如果集合中不存在这样的元素,它们将返回null
:
var b2 = list.OfType<B2>().FirstOrDefault(); // or First()
顺便说一句,如果您看一下OfType<>
的实现,您会发现它返回OfTypeIterator
,并且在该方法内部,它仅遍历集合并使用is
运算符以找出具有所需类型的对象:
static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source) {
foreach (object obj in source) {
if (obj is TResult) yield return (TResult)obj;
}
}
最后,请注意,在这种情况下,使用as
关键字会带来更好的性能。但是,如果首先使用OfType<>
,is
运算符检查类型,然后进行转换。因此,如果性能对您很重要,则可以继续使用自己的实现。