How to cast List<object> to List<SomethingElse> - c#

How can i cast a List<object> to List<SomethingElse>?
(where SomethingElse is known to descend from object)
Bonus Chatter
Casting the list:
List<Object> first = ...;
List<SomethingElse> second = (List<SomethingElse>)first;
doesn't work:
Cannot convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
Casting the list:
List<SomethingElse> second = first.Cast<SomethingElse>();
doesn't work:
Cannot implicitely convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
i don't actually need the full List<T> object, just an ICollection<T> will do:
ICollection<SomethingElse> second = first;
ICollection<SomethingElse> second = (ICollection<SomethingElse>)first;
ICollection<SomethingElse> second = first.Cast<SomethingElse>();
don't work.

LINQ, as implemented through the extension methods within the Enumerable class, relies on deferred execution:
Methods that are used in a query that returns a sequence of values do not consume the target data until the query object is enumerated. This is known as deferred execution.
Cast<T> does not create a new list immediately, but rather stores all the information that is required to perform the action. The list would only get enumerated when required (for example, through a foreach statement).
In your case, if you simply intend to iterate over the sequence, you should consider sticking to the IEnumerable<T> interface, which is the declared return type of Cast<T>:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
foreach (SomethingElse se in second)
{
// ...
}
This is efficient, since it only performs the cast as each item is iterated.
If you’re convinced you want a new list to be created immediately, use ToList:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();
Edit: Replying to point posted in comment:
It depends on what you mean by “a list that can be modified”. There are several LINQ query operators that will allow you to alter the definition of your query further. For example, if you want to remove all SomethingElse elements whose IsDeleted property is true, you can use the Where operator:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
second = second.Where(element => !element.IsDeleted);
If you want to add a sequence of new elements, you can use the Concat operator:
second = second.Concat(anotherCollectionOfSomethingElse);
If you want to sort your sequence in ascending order of ID, use the OrderBy operator:
second = second.OrderBy(element => element.ID);
Each time, we’re applying a query operator over the former definition of our query, and assigning the new (composite) query to our second variable. LINQ would store all your operators in the query definition. Then, when the sequence is actually enumerated (for example, through a foreach or ToList), it would give you the composite result of your sequence, with all the query operators applied in order.
As with all cases of deferred execution / lazy evaluation, be careful not to go overboard with this. If, for example, you’re going to apply a Where operator which will reduce the size of your sequence drastically, it might make sense to execute the query eagerly and store the enumerated list instead.

You have the option of using either Cast or OfType. Cast will throw an exception if you cannot cast to the type specified. OfType on the other hand will return only those items in the list that can be cast to the specified type. I would recommend using OfType in your situation.
List<Foo> fooList = myList.OfType<Foo>().ToList();

I think you're close with the Cast<T> expression. The difference is that Cast<T> returns an IEnumerable<T>, not a List<T>.
Try this:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
You can get a list by doing something similar:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();

Related

Understanding two methods with LINQ and lambda

I have a question, my friend and I are doing code, and he did two methods that I don't exactly understands.
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = (from bor in list group bor by new { bor.BookAccessor, bor.ReaderAccessor } into dist select dist.First()).ToList();
return Result;
}
and a second one
public static List<Borrow> GetDistinctBorrows(List<Borrow> list)
{
var Result = list.GroupBy(x => new { x.ReaderAccessor, x.BookAccessor }).Select(y => y.First()).ToList();
return Result;
}
Those methods have the same functionality, but one are written with LINQ, and a second one with lambda expressions.
Can someone explain to me, how they work (especially the fragment with 'new' word)?
The part with new word is how you define instances on Anonymous Types.
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.
You create anonymous types by using the new operator together with an object initializer. For more information about object initializers, see Object and Collection Initializers (C# Programming Guide).
As a side note, your queries are equivalent, because compiler will transform the first one onto the second one as part of compilation process. Read more about that on MSDN: Query Syntax and Method Syntax in LINQ (C#)
Most queries in the introductory Language Integrated Query (LINQ) documentation are written by using the LINQ declarative query syntax. However, the query syntax must be translated into method calls for the .NET common language runtime (CLR) when the code is compiled. These method calls invoke the standard query operators, which have names such as Where, Select, GroupBy, Join, Max, and Average. You can call them directly by using method syntax instead of query syntax.
The functions gets a list of distinct items from the input list, where ReaderAccessor and BookAccessor determine equality. Duplicated items from the input list is discarded.
They work by grouping by a new anonymous object defined by the two properties (this is where the new keyword is used), creates an alias dist and then taking the first one, essentially discarding the rest.

Does usage of contains on IEnumerable cast it to a List?

I'm using Linq to filter Data I get from the database. Due to design choices made 1 method returns me an IEnumerable<int> which I then use for a linq statement to see which IDs are permitted to be returned (code follows below). My question here is as I'm not seeing anything there in the documentation: Does the Contains method implicitly cast the IEnumerable to a List for the statement to be executed? (If so the question is if using List in the first place instead of IEnumerable is better).
Code Example
private List<MyData> GetAllPermittedData()
{
IEnumerable<int> permitteddIds = GetPermittedIDs();
return (from a in MyDataHandler.GetAllData() where permittedIds.Contains(a.Id)
select a);
}
Like I asked above I'm not sure if the Contains part implicitly converts permittedIds into a List<int> (for/inside the use of the Contains statement). If this is the case then a followup question would be if it is not better to already use the following statement instead (performance-wise):
private List<MyData> GetAllPermittedData()
{
List<int> permitteddIds = GetPermittedIDs().ToList();
return (from a in MyDataHandler.GetAllData() where permittedIds.Contains(a.Id)
select a);
}
The LINQ operator will attempt to cast it to ICollection<T> first. If the cast succeeds, it uses that method. Since List<T> implements this interface, it will use the list's contain method.
Note that if you use the overload that accepts an IEqualityComparer, it must iterate over the enumerable and the ICollection shortcut is not taken.
You can see this implementation in the .NET Framework reference source:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value) {
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) return collection.Contains(value);
return Contains<TSource>(source, value, null);
}
Jon Skeet also has a good (and lengthy) blog series called "Reimplementing LINQ" where he discusses the implementation in depth. He specifically covers Contains in part 32 of his blog.
The Contains method may try to cast the passed IEnumerable<T> to IList<T> or to ICollection<T>. If the cast succeeds, it may directly use the methods of IList<T>, otherwise it will enumerate over the full sequence.
Note that I am writing may because this is implementation-specific and it is not specified in the docs. As such, it could be different across .NET versions and also in alternative implementations such as Mono.
Your advantage by providing only an IEnumerable<T> is that you have more freedom to exchange the object returned from that property without changing the public interface. The performance cost of the attempted cast to IList<T> or similar should be negligible.
In any case, this way is more performant than your suggestion of calling ToList, as that will actually create a new List<T> and copy all items from the enumeration into it.
Contains exists as an extension method for IEnumerable<T>. But you con't need to convert your IEnumerable to a List<T> with ToList(), you could simply use that IEnumerable<T> to fill a HashSet<T>:
var permitteddIds = new HashSet<int>(GetPermittedIDs());

How to convert unioned generic list to generic list?

I have two generic list that have been unioned. Say listA and listB, both of type List<SomeType>.
listA.Union(listB);
The unioned set is of type System.Linq.Enumerable.UnionIterator<string>, which isn't the same as List<SomeType>.
I have tried casting:
listA.Union(listB).ToList<SomeType>();
and
(List<SomeType>)listA.Union(listB);
Both fail. I tried to access ForEach(), thinking I could add the result to a new list. .Foreach() isn't available.
I could use a traditional foreach and add each item to a List<SomeType> variable. However, is there a lambda statement that can do the conversion in one line, assigning to a variable of type List<SomeType>?
You don't have to explicitly cast the List in ToList method. If both the list are of same type, you can simply do ToList in the end to get a List of the same type.
List<MyClass> listA = new List<MyClass>();
List<MyClass> listB = new List<MyClass>();
List<MyClass> temp = listA.Union(listB).ToList(); //Just do ToList at the end.
Explicitly specifying the type in ToList method should work as well. I am not sure why its not working.
Union is an extension method on IEnumerable<T> interface, not on List<T>, so it doesn't know or care that you are trying to connect lists and thus does not create one as a result unless you call ToList explicitly.
If you want to 'attach' one list to another, you might want to use AddRange method instead.

Why do LINQ operations lose the static type of the collection?

Regardless of the collection type I use as input, LINQ always returns IEnumerable<MyType> instead of List<MyType> or HashSet<MyType>.
From the MSDN tutorial:
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// numQuery is an IEnumerable<int> <====== Why IEnumerable<int> instead of int[]?
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
I wonder what's the rationale behind the decision to not preserve the collection type (like the element type), not the suggested work-around.
I know that toArray, toDictionary or toList exist, that's not the question.
Edit: How does the implementation in C# differ from Scala where it works without overriding the return types everywhere?
Linq standard query operators are defined on IEnumerable<T>, not on any other specific collection type. It is applicable to most collections because they all implement IEnumerable<T>.
The output of these standard query operators is a new IEnumerable<T> - if you want to support all collections available, you would need N implementations of those standard query operators, not just one.
Also many aspects of Linq, like lazy evaluation would not work well if forced to work an i.e. a List<T> as opposed to an IEnumerable<T>.
Short answer: C#'s type system is too primitive to support preservation of collection type in higher order functions (without code duplication, that is).
Long answer: Refer to my post here. (Actually it's about Java, but applies to C# as well.)
In the specific case of LINQ-to-objects, the LINQ-provider is a set of extension method defined in the System.Linq.Enumerable class. To be as general purpose as possible, they are defined to extend any type which implements the IEnumerable<T> interface. Therefore, when these methods are executed, they aren't aware of which concrete type the collection is; it only knows that it is IEnumerable<T>. Because of this, the operations you perform on a collection cannot be guaranteed to produce a collection of the same type. So instead, it produces the next best thing - a IEnumerable<T> object.
This was a very specific design choice. LINQ is intended to work at a very high level of abstraction. It exists so that you don't have to care about underlying sources of data, but can instead just say what you want and not care about such details.
LINQ takes an IEnumerable<> and returns one. Very natural. The reason IEnumerable is what LINQ takes- pretty much all collections implement it.
Many System.Linq.Enumerable methods are lazily evaluated. This allows you to create a query without executing it.
//a big array - have to start somewhere
int[] source = Enumerable.Range(0, 1000000).ToArray();
var query1 = source.Where(i => i % 2 == 1); //500000 elements
var query2 = query1.Select(i => i.ToString()); //500000 elements
var query3 = query2.Where(i => i.StartsWith("2"); //50000? elements
var query4 = query3.Take(5); //5 elements
string[] result = query4.ToArray();
This code calls ToString about 15 times. It allocates a single string[5] array.
If Where and Select returned arrays, this code would call ToString 500000 times and have to allocate two massive arrays. Thank goodness that is not the case.

Extension Method ConvertAll

What is the proper use of ConverAll ? Will it convert one type to another type?
like
List<int> intList = new List<int>();
intList.Add(10);
intList.Add(20);
intList.Add(30);
intList.Add(33);
var query= intList.ConvertAll(x=>(double)x);
for this i can use cast or OfType<>.
ConvertAll isn't an extension method, it's a real method on List<T> itself.
It returns a new list containing the converted elements. So in your example, the query variable isn't actually a query, it's a List<double>.
Cast and OfType are extension methods that operate on IEnumerable and return an IEnumerable<T>. However they're not suitable for your stated purpose: Cast can convert reference types but cannot convert value types, only unbox them. OfType doesn't perform any conversion, it just returns any elements that are already of the specified type.
ConvertAll will just call your delegate/anonymous method for each element of the list. What this does is entirely up to you.
In the example code you posted, it will attempt to cast each element to a double and return that, which means you'll get a List<Double> in return.
You should not use OfType<T>, since this will filter the elements based on the type, and will only return a different type than the original if it is type compatible due to inheritance or interface implementation.
In other words, .OfType<Double> will return no elements, since none of the ints are also doubles.
ConvertAll is a projection operator and maps most closely to LINQ's Select. LINQ's Cast is a specific projection operator and represents doing what you did [via projection] - or it would (as pointed out in Luke's answer [and comment], which I +1'd) if you weren't converting to a value type.
In general, LINQ has a more complete and well-thought-through set of operators, which makes older stuff like ConvertAll look a bit silly at times [like this]. (or #stoopid :D).
to my knowledge, OfType<T> will only return the elements in the collection that are of the specified type T.
ConvertAll allows you to convert the elements to another type.

Categories

Resources