简体   繁体   中英

Linq cast to list<T>

I have the following classes:

public class Column
{
    public String Name;
    public String Value;
}

public class ColumnList : List<Column> {}

Then I do:

var cols = (from c in othercolumnlist
            select new Column
            {
               Name = c.Name,
            }).ToList() as ColumnList;

However it returns null. How can I successfully cast into my list?

ColumnList is a List<Column> but List<Column> is not a ColumnList . Consider Animal and Dog classes:

public class Animal
{
}

public class Dog: Animal
{
}

What you are trying to do is treat any animal as dog. But not all animals are dogs. There can be Cat or Kangaroo . Thats why as ColumnList returns null .

You need to create new ColumnList instance instead and add columns to it manually:

var columnList = new ColumnList();
columnList.AddRange(othercolumnlist.Select(c => new Column { Name = c.Name }));

If you need to do this often, then you can add static creation method to your ColumnList class:

public static ColumnList CreateFrom(ColumnList other)
{
     var columnList = new ColumnList();
     columnList.AddRange(other.Select(c => new Column { Name = c.Name }));
     return columnList;
}

And use it this way:

var columnList = ColumnList.CreateFrom(otherColumnList);

What you're trying to do is equivalent to this:

Animal animal = new Animal();
Dog dog = animal as Dog;

One possible solution is to provide a constructor that takes an existing list, and calls the base constructor, such as:

public class ColumnList : List<Column>
{
    public ColumnList(IEnumerable<Column> collection):
         base(collection)
    {
    }
}

And then build your ColumnList from an existing collection.

var collection = othercolumnlist.Select(c => new Column { Name = c.Name });

var columnList = new ColumnList(collection);

You could also provide an extension method to make this easier:

public static class ColumnListExtensions
{
    public static ToColumnList(this IEnumerable<Column> collection)
    {
        return new ColumnList(collection);
    }   
}

var cols = othercolumnlist.Select(c => new Column { Name = c.Name })
           .ToColumnList();

What you are trying to do is down-cast List<Column> to ColumnList which assumes that all List<T> 's are ColumnList 's - which obviously they aren't.

What you can do however is initialize a new instance of ColumnList by passing the result of your query

new ColumnList().AddRange(othercolumnlist
    .Select(x => new Column { Name = x.Name })
    .ToList());

You could if you define a copy constructor for your ColumnList type:

public class ColumnList : List<Column>
{
    public ColumnList(IEnumerable<Column> src) : base(src)
    {
    }
}

And you then do:

var cols = new ColumnList(from c in othercolumnlist
            select new Column
            {
               Name = c.Name,
            }).ToList());

Reason being ToList() returns a List and not a ColumnList . It can only ever be a ColumnList if you explicitly instantiate it as one, but never vice-versa.

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