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