Pathan
Pathan

Reputation: 75

How to cast List<A> to List<B>

How do I cast List<SelectVacancyDetails_Result> to List< SelectVacancyDetails_ResultExtend> where class SelectVacancyDetails_ResultExtend is inherited from class SelectVacancyDetails_Result.

I tried below but no luck

   List<SelectVacancyDetails_ResultExtend> vacExtList = vacList.Cast<SelectVacancyDetails_ResultExtend>().ToList();

(Basically i want all list properties value to be copied over)

Upvotes: 1

Views: 304

Answers (8)

Aydin
Aydin

Reputation: 15294

Here's an example using AutoMapper

private static void Main(string[] args)
{
    Mapper.CreateMap<Foo, FooBar>();

    List<Foo> randomFoos = new List<Foo>();

    for (int i = 0; i < 10; i++)
    {
        randomFoos.Add(new Foo());
    }

    Console.WriteLine("### Random foos");
    randomFoos.ForEach(Console.WriteLine);

    Console.WriteLine("### Converted foos");
    Mapper.Map<List<FooBar>>(randomFoos)
            .ForEach(Console.WriteLine);
}

public class Foo
{
    public Foo()
    {
        this.Id = Guid.NewGuid().ToString();
        this.Name = Guid.NewGuid().ToString("n")
                        .Substring(6);
    }

    public string Id { get; set; }
    public string Name { get; set; }

    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();
        this.GetType()
            .GetProperties()
            .ToList()
            .ForEach(property => builder.AppendLine(string.Format("{0}: {1}", property.Name, property.GetValue(this))));

        builder.AppendLine();

        return builder.ToString();
    }
}

public class FooBar : Foo
{
    public FooBar()
    {
        this.Description = Guid.NewGuid().ToString()
                                .Substring(12);
    }

    public string Description { get; set; }
}

Upvotes: 0

Fabjan
Fabjan

Reputation: 13676

It's a typical problem. Other then use constructor in your derived class or 3rd party libs like AutoMapper you can also create your custom extension method with Reflection it'd much slower so don't use it if you're working with in bottleneck of some sort and use it only if performance is not something that you aren't really worry about or if you can't modify your derived class and by some reason don't want to use AutoMapper. These example covers only typical EF models with properties (no fields).

So the method is :

public static class Helper
{
    public static IEnumerable<T2> ConvertRange<T1, T2>(this IEnumerable<T1> collection)
        where T1 : class
        where T2 : class, new()
    {
        List<T2> elements = new List<T2>();

        PropertyInfo[] propsT2 = typeof(T2).GetProperties();
        PropertyInfo[] propsT1 = typeof(T1).GetProperties()
            .Where(p => propsT2.Any(p2 => p2.Name == p.Name)).ToArray();

        propsT1.OrderBy(p => p.Name);
        propsT2.OrderBy(p => p.Name);

        foreach (T1 item in collection)
        {
            T2 newEl = new T2();

            for (int i = 0; i < propsT1.Length; i++)
                propsT2[i].SetValue(newEl, propsT1[i].GetValue(item));

            elements.Add(newEl);
        }

        return elements;
    }
}

Example :

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class Manager
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    static void Main(string[] args)
    {
        List<Person> ps = new List<Person>()
        {
            new Person() { Name ="Alex", Age = 30 },
            new Person() { Name ="Michael", Age = 22 }
        };

        List<Manager> mgr = ps.ConvertRange<Person, Manager>().ToList();

        foreach (var item in mgr)
            Console.WriteLine(item.Name + "   " + item.Age);

        Console.ReadKey();
   }

}

Output :

Alex     30
Michael  22

Upvotes: 0

Michał Jarzyna
Michał Jarzyna

Reputation: 1916

It is not possible. However you can try this solution:

 class Program
{
    static void Main(string[] args)
    {
        var vacancies = new List<Vacancy>
        {
            new Vacancy {Id = 1, Details = "flat"},
            new Vacancy {Id = 2, Details = "restaurant"}
        };


        List<VacancyExtended> vacanciesExtended = vacancies.Select(p => new VacancyExtended(p)).ToList();


        foreach (var v in vacanciesExtended)
        {
            Console.WriteLine(v.Details);

        }
        Console.ReadKey();
    }
}


public class Vacancy
{
    public int Id { get; set; }
    public string Details { get; set; }

    public Vacancy(){ }
    public Vacancy(Vacancy vacancy)
    {
        Id = vacancy.Id;
        Details = vacancy.Details;
    }
}
public class VacancyExtended : Vacancy
{
    public VacancyExtended(Vacancy vacancy) : base(vacancy)
    {

    }

    public string AdditionalInfo { get; set; }
}

Upvotes: 0

Fabio Salvalai
Fabio Salvalai

Reputation: 2509

If stack item's solution doesn't work, it's perfhaps because one of the item can't be casted. (Maybe it's an instance of a less specific type)

what you could do is only get the element that could be casted, and use the following code:

var vacExtList = vacList.OfType<SelectVacancyDetails_ResultExtend>();

EDIT:

This solution assumes that SelectVacancyDetails_ResultExtend inherits from SelectVacancyDetails_Result, obviously.

Upvotes: 0

Anton Gogolev
Anton Gogolev

Reputation: 115779

Inheritance does not work that way. With class Derived : Base, it is not possible to "cast" an object with runtime type Base to Derived. You'll need to either copy all properties manually or use something like AutoMapper.

Upvotes: 1

Paddy
Paddy

Reputation: 33867

You can't do this, if as you have stated:

SelectVacancyDetails_ResultExtend inherits SelectVacancyDetails_Result

Then you can't cast an object of type SelectVacancyDetails_Result to type SelectVacancyDetails_ResultExtend.

You can cast SelectVacancyDetails_ResultExtend to type SelectVacancyDetails_Result, but not the other way.

You will need to project your properties into the list of base class items instead:

var vacExtList = vacList.Select(v => new SelectVacancyDetails_ResultExtend() {
   PropertyA = v.PropertyA,
   ...
});

I would also note that having a need to do this is a bit of a code smell - there is something wrong with your inheritance chain.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500923

If all the elements are actually of type SelectVacancyDetails_Result (not SelectVacancyDetails_ResultExtend) then you can't just cast. The simplest approach would be to create a constructor in SelectVacancyDetails_ResultExtend which copied the properties - or just used composition instead of inheritance, potentially - and then you can use:

var vacExtList = vacList.Select(vac => new SelectVacancyDetails_ResultExtend(vac))
                        .ToList();

Upvotes: 7

stack item
stack item

Reputation: 564

List<SelectVacancyDetails_ResultExtend> vacExtList = vacList.Select(x => (SelectVacancyDetails_ResultExtend)x).ToList();

Upvotes: 0

Related Questions