I have an abstract class:
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);
}
}
and I have a List<A> a
and I want to get a first item of given type 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.");
}
Is there a way to do it?
Edit:
It shows: The type parameter 'T' cannot be used with the 'as' operator
because it does not have a class type constraint nor a 'class'
constraint
Don't use as
for checking the type. Use is
instead:
if (item is T)
return (T)item;
Here is the detailed explanation about Type casting in msdn.
For making your code to work you have to add where
constraint to your method:
static T GetTypeFromList<T>(List<A> a) where T: class
and then it will work.
Because, as you are using as
keyword, it converts the object to a given reference or nullable value type. In case of failed conversion the result of as
operator will be null
. And null
is valid only for nullable types. For satisfying the compiler you have to add class
constraint to your method signature.
But, there is already built-in method exits in System.Linq
namespace for that purpose. It is called OfType<>
. It filters the elements of an IEnumerable
based on a specified type.
var b2s = list.OfType<B2>();
And for getting the first item you can make use of First()
or FirstOrDefault()
which will return null
if such element is not exist in the collection:
var b2 = list.OfType<B2>().FirstOrDefault(); // or First()
By the way, if you will take a look to the implementation of OfType<>
you will see that it returns OfTypeIterator
and inside that method it just iterates over the collection and uses is
operator to find out the objects with desired type:
static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source) {
foreach (object obj in source) {
if (obj is TResult) yield return (TResult)obj;
}
}
At the end would like to note, using as
keyword will give better performance in that situation. But in case OfType<>
, is
operator is used at first to check the type and then conversion will happen. So, if performance is important for you, you can continue to use your own implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With