简体   繁体   中英

C# Generics typecast List<T> to List< BaseType>

How can i typecast List<Car> to List<MyBaseClass> , In my code instance of List will go as an object (program requirement not intentional), by doing this i will retrieve vehicleId..

 public Form1()
    {           
        List<Car> lstCar = new List<Car>();
        lstCar.Add(new Car() { Make = "tootay", Model = "camry", VechicleId = 1 });
        lstCar.Add(new Car() { Make = "honda", Model = "civic", VechicleId = 2 });
        VehicleConverter(lstCar);
    }
    public void VehicleConverter(object obj)
    {
      //Want to typecast it to List<MyBaseClass>            
    }        
}

public class MyBaseClass
{        
    public int VechicleId { get; set; }        
}

public class Car:MyBaseClass
{
    public string Make { get; set; }
}

public class Bike : MyBaseClass
{
    public int CC { get; set; }
}

This is not possible.

Had it been possible, you would be able to write the following:

List<Car> carList = new List<Car>();
List<BaseClass> baseList = (List<BaseClass>)carList;
baseList.Add(new Bike());    //I just put a Bike into a List<Car>!

Alternatives:

  • Declare the list as List<BaseCLass>
  • Cast to a non-generic IList (not recommended)
  • Cast to IEnumerable<BaseClass> , using .Net 4's covariance
  • Pass a typed copy of the list:

     VehicleConverter(lstCar.ConvertAll(c => (BaseClass)c)); 

You didn't mention if you're using .NET 4.0 or earlier, but if you are using .NET 4.0 then the new co-variance/contra-variance feature for generic interfaces may help you.

You've discovered that you can't cast List<Car> as List<MyBaseClass> , but with .NET 4.0 you can cast IEnumerable<Car> as IEnumerable<MyBaseClass> .

You could then call functions that require an IEnumerable<MyBaseClass> with your List<Car> as the parameter without doing any special conversion or casting code.

For example, this code works in .NET 4.0:

List<Car> lstCar = new List<Car>();
lstCar.Add(new Car() { Make = "tootay", Model = "camry", VechicleId = 1 });
lstCar.Add(new Car() { Make = "honda", Model = "civic", VechicleId = 2 });

VehicleConverter(lstCar);

public void VehicleConverter(IEnumerable<MyBaseClass> vehicles)
{
    var found = vehicles.Where(v => v.VechicleId == 123);
}

I hope this helps.

And the reason why this is not possible is because you could runtime errors like this:

var cars = new List<Car>();
var vehicles = (List<MyBaseClass>)cars; // Not possible, but assume it was
vehicles.Add(new Bike());  // Runtime fail because now you are trying to add a bike to a list of cars
public List<MyBaseClass> VehicleConverter<T>(List<T> obj)
    where T : MyBaseClass
{
    return obj.Cast<MyBaseClass>().ToList();
} 

You could try using the "IEnumerable.Cast<T>()" extension method from the System.Linq namespace.

Here is a link to the msdn documentation: http://msdn.microsoft.com/en-us/library/bb341406.aspx

Here is an example:

public void VehicleConverter(IEnumerable obj)
{
     IEnumerable<MyBaseClass> enumerable = obj.Cast<MyBaseClass>();
     List<MyBaseClass> list = enumerable.ToList();
}

This works

if (obj is List<Car>)
{
    List<MyBaseClass> c = ((List<Car>)obj).ToList<MyBaseClass>();
}

But you would need to do it for each type. Ideally you should cast before passing to VehicleConverter.

Seems like an odd requirement though and would suggest @yodaj007 option if you are allowed to use that.

Even though i could not convert it to BaseClass, but i achieved my objective of retrieving the vehicleId by Casting & Reflection.

    public void VehicleConverter(object obj)
    {

        Type t = obj.GetType().GetGenericArguments()[0].GetType();
        IList lstVec = ((IList)obj);
        foreach (var k in lstVec)
        {
            PropertyInfo[] p = k.GetType().GetProperties();
            foreach (PropertyInfo pi in p)
                if (pi.Name == "VechicleId")
                    MessageBox.Show(Convert.ToString(pi.GetValue(k, null)));
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM