如何将抽象类转换为T类型?

时间:2019-12-28 15:57:01

标签: c#

我有一个抽象类:

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”运算符一起使用           因为它没有类类型约束也没有“类”           约束

3 个答案:

答案 0 :(得分:4)

请勿使用as检查类型。请改用is

if (item is T)
    return (T)item;

Here是有关msdn中的类型转换的详细说明。

答案 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运算符的结果将为nullnull仅对可为空的类型有效。为了使编译器满意,您必须在方法签名中添加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运算符检查类型,然后进行转换。因此,如果性能对您很重要,则可以继续使用自己的实现。