Shekhar Pankaj
Shekhar Pankaj

Reputation: 9145

How to Cast List<T> To List<ClassName>

I am using generic method to fill my dropdown for all types

below is my code.

the entity type are as follow

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

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

i am able to fetch data successfully at
var data = DataFetcher.FetchData<T>();

private static void Main( string[] args )
{
    List<DropDown> cities = BLL.GetDataList<City>();
    List<DropDown> states = BLL.GetDataList<State>();
    List<DropDown> roles = BLL.GetDataList<Role>();
}

public static class BLL
{
    public static List<DropDown> GetDataList<T>() where T : class ,new()
    {
        var data = DataFetcher.FetchData<T>();
        return data as List<DropDown>;
    }
}

I knew this cast data as List<DropDown> will fail,thats why its returning null back to calling method,

How can i cast Generic list to List of Known Type?

Upvotes: 0

Views: 435

Answers (3)

Yacoub Massad
Yacoub Massad

Reputation: 27871

One solution is to use AutoMapper.

First create a map between your models like this:

AutoMapper.Mapper.CreateMap<Role, DropDown>();

Do the same thing for City and State classes if you need to.

Then you can use AutpMapper to convert your objects to DropDown like this:

public static List<DropDown> GetDataList<T>() where T : class ,new()
{
    var data = DataFetcher.FetchData<T>();
    return data.Select(x => AutoMapper.Mapper.Map<DropDown>(x)).ToList();
}

Upvotes: 1

CodeCaster
CodeCaster

Reputation: 151720

You have to ask yourself: how do I want to convert T to DropDown? If you can't answer this, the answer is: you can't.

I guess your DropDown class has an object Value property, that holds the dropdown value, and you wish to assign the data entity to that property.

Then you can project the list of data entities to DropDowns as such:

var data = DataFetcher.FetchData<T>();
return data.Select(d => new DropDown { Value = d }).ToList();

As for your edit: so you have at least one type, the displayed Role, that has an Id and Name property. But type T doesn't guarantee this, so you'd need to introduce an interface:

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

And apply this to your entities. Then introduce it as a generic constraint and do the mapping:

return data.Select(d => new DropDown
{ 
    Id = d.Id,
    Name = d.Name,
}).ToList();

But you don't want this, as here you are tying these two properties to dropdowns. Tomorrow you'll want an entity with Code instead of Id and Text instead of Name, so you'll have to add more interfaces, more overloads, and so on.

Instead you might want to use reflection, where you can specify the member names in the call:

List<DropDown> cities = BLL.GetDataList<City>(valueMember: c => c.CityCode, displayMember: c => c.FullCityname);

And use these member expressions to look up data's values and fill those into the DropDown.

However, you're then reinventing the wheel. Leave out your DropDown class entirely, and leave the dropdown generation to the front end, in this case MVC:

var cities = DataFetcher.FetchData<City>();

var selectList = new SelectList(cities.Select(c => new SelectListItem
{
    Selected = (c.Id == selectedCityId),
    Text = c.FullCityName,
    Value = c.CityCode,
});

Or:

var selectList = new SelectList(cities, "CityCode" , "FullCityName", selectedCityId);

Upvotes: 3

Codor
Codor

Reputation: 17605

If I understood the question correctly, you could use Linq as follows.

return data.Cast<DropDown>().ToList();

Upvotes: 0

Related Questions