Best way to convert IList or IEnumerable to Array - c#

I have a HQL query that can generate either an IList of results, or an IEnumerable of results.
However, I want it to return an array of the Entity that I'm selecting, what would be the best way of accomplishing that? I can either enumerate through it and build the array, or use CopyTo() a defined array.
Is there any better way? I went with the CopyTo-approach.

Which version of .NET are you using? If it's .NET 3.5, I'd just call ToArray() and be done with it.
If you only have a non-generic IEnumerable, do something like this:
IEnumerable query = ...;
MyEntityType[] array = query.Cast<MyEntityType>().ToArray();
If you don't know the type within that method but the method's callers do know it, make the method generic and try this:
public static void T[] PerformQuery<T>()
{
IEnumerable query = ...;
T[] array = query.Cast<T>().ToArray();
return array;
}

Put the following in your .cs file:
using System.Linq;
You will then be able to use the following extension method from System.Linq.Enumerable:
public static TSource[] ToArray<TSource>(this System.Collections.Generic.IEnumerable<TSource> source)
I.e.
IEnumerable<object> query = ...;
object[] bob = query.ToArray();

I feel like reinventing the wheel...
public static T[] ConvertToArray<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
throw new ArgumentNullException("enumerable");
return enumerable as T[] ?? enumerable.ToArray();
}

In case you don't have Linq, I solved it the following way:
private T[] GetArray<T>(IList<T> iList) where T: new()
{
var result = new T[iList.Count];
iList.CopyTo(result, 0);
return result;
}
Hope it helps

Related

Return same Type as Generic Class

Wasn't really sure how to phrase the title.
What I am trying to achieve is a deep clone system for IEnumerable<T>s where T:ICloneable.
I have written the, as-yet untested, method below which I believe should work:
public static IEnumerable<T> DeepClone<T>(this IEnumerable<T> source) where T:ICloneable
{
return source.Select(s => (T) s.Clone());
}
However, this returns an IEnumerable<T> (as one would expect) and I am curious as to whether or not it is possible (without causing an unacceptable overhead) to return the base type of the IEnumerable<T> instead.
For example, running List<int>.DeepClone() would return a new, cloned List<int> and running int[].DeepClone() would return a new, cloned int[].
I know that I can quite easily just cast my IEnumerables after calling this method, but I'm hoping to be able to avoid this.
There is also the option of creating a whole load of overloads, one for each IEnumerable but if it's possible to I'd like to avoid this.
You will need to build explicit methods for the concrete types you want to support (List, arrays etc).
An example:
public static List<T> DeepClone<T>(this List<T> source) where T : ICloneable
{
return source.Select(s => (T)s.Clone()).ToList();
}
Alternatively, use an approach like:
public static IEnumerable<T> DeepClone<T>(this IEnumerable<T> source) where T : ICloneable
{
var result = source.Select(s => (T)s.Clone());
if (source is List<T>)
{
return result.ToList();
}
return result;
}

Do we have a "Contains" method in IEnumerable

I have a class in my code that is already deriving from IEnumerable.
I was wondering if there is a way that I can use a "Contains" method on its instnaces to look for a something in that list?
Do you really implement the non-generic IEnumerable, or the generic IEnumerable<T>? If you can possibly implement the generic one, your life will become a lot simpler - as then you can use LINQ to Objects, which does indeed have a Contains extension method.
Otherwise, you could potentially convert from the non-generic to generic using Cast or OfType, e.g.
bool found = nonGeneric.Cast<TargetType>().Contains(targetItem);
It would be nicer if you just implemented the generic interface to start with though :)
No, there's no such method in the IEnumerable<T> interface. There's an extension method though that you could use.
using System.Linq;
and then:
IEnumerable<string> foos = new[] { "foo", "bar", "baz" };
bool IsThereABar = foos.Contains("bar");
public static bool Contains<T>(this IEnumerable source, T value)
{
foreach (var i in source)
{
if (Equals(i, value))
return true;
}
return false;
}
If you want, you can add custom comparer as parameter ti extension method Contains

Where is the ToList() method? (IQueryable)

If I try this, it will work:
var query = myContextObject.Users.Where(u=>u.Name == "John");
query.ToList();
I'm able to call ToList and a lot of other extension methods.
But if I try this:
public List ConvertQueryToList(IQueryable query)
{
return query.ToList();
}
ToList won't be accessible, I'm guessing this is because ToList is an extension method, but then how is that ToList is attached in the first example?
Is it possible to access ToList in the second case?
You need to write it as:
public List<T> ConvertQueryToList<T>(IQueryable<T> query)
{
return query.ToList();
}
This will cause the IQueryable<T> to return the appropriate List<T>, since the Enumerable.ToList() method requires an IEnumerable<T> as input (which also works with IQueryable<T>, as IQueryable<T> inherits IEnumerable<T>).
That being said, there is really no reason to use it this way. You can always just call ToList() directly if you need to create a List<T> - abstracting inside of a second layer just confuses the API further.
If you're trying to convert a non-generic IQueryable interface, you would need to do something like:
public List<T> ConvertQueryToList<T>(IQueryable query)
{
return query.Cast<T>.ToList();
}
This would then require calling like:
var results = ConvertQueryToList<SomeType>(queryable);
Alternatively, if you want to leave this non-generic (which I wouldn't recommend), then you could use:
public ArrayList ConvertQueryToList(IQueryable query)
{
ArrayList results = new ArrayList();
results.AddRange(query.Cast<object>().ToList());
return results;
}
The first of your examples returns an IQueryable<T>, whereas in the second you're using IQueryable (without the Generic Type parameter).
You can check out the two completely different interfaces here and here.
Here is an extension method for this:
public static class ListHelper
{
public static IList ToList(this IQueryable query)
{
var genericToList = typeof(Enumerable).GetMethod("ToList")
.MakeGenericMethod(new Type[] { query.ElementType });
return (IList)genericToList.Invoke(null, new[] { query });
}
}
Here is a generic extension method for the case you are using IQueryable<>.
Of course it is not absolutely safe because the type could be wrong and the cast could fail. So please be careful if you use that method.
using System.Collections.Generic;
namespace System.Linq
{
public static class Extensions
{
public static List<T> ToList<T>(this IQueryable queriable)
{
return ((IQueryable<T>)queriable).ToList();
}
}
}

Casting List<MyObject> to IEnumerable<MyInterface>

I'm still learning some of this c# stuff, and I couldn't find an answer to this question. Assuming that I have a list of MyObject implementing MyInterface
public class MyObject : IMyInterface { ...}
public List<MyObject> MyObjectList;
How can I return an IEnumerable<IMyInterface> with the contents of MyObjectList?
I mean, right now I have this:
List<IMyInterface> temp = new List<IMyInterface>();
foreach (MyObject obj in MyObjects) temp.Add(obj);
return (IEnumerable<IMyInterface>)temp;
But is it necessary to create a new list like this?
Thank you.
If you're using .NET 3.5, the easiest way to do this is:
return MyObjects.Cast<IMyInterface>();
You don't need to create a copy of everything - but until C# 4 comes out with its generic interface variance, you're stuck doing something like this.
If you're still using .NET 2.0, you can easily do something similar:
public static IEnumerable<TResult> SafeCast<TSource, TResult>
(IEnumerable<TSource> source) where TResult : TSource
{
foreach (TSource item in source)
{
yield return item;
}
}
(Note that this doesn't check for source being null; to do that properly you'd want two methods due to the deferred execution of iterator blocks.)
Then use:
return SafeCast<MyObject, IMyInterface>(MyObjects);
You could make it more like the LINQ version, like this:
public static IEnumerable<T> SafeCast<T>(IEnumerable source)
{
foreach (T item in source)
{
yield return item;
}
}
return SafeCast<IMyInterface>(MyObjects);
This has compile-time safety though - it wouldn't stop you from trying to convert a List<string> into an IEnumerable<Guid> for example.
Using the LINQ Cast method works well here, something like MyObjects.Cast()
If you're using C# 3 and .NET 3.5 (or above), then you can use the LINQ suggestion that Jake presented:
return MyObjectList.Cast<IMyInterface>();
(There's no need for AsEnumerable in this particular circumstance)
However, if you're using a prior version (2.0 of C# and .NET or above), you can still use an iterator block:
foreach(MyObject obj in MyObjectList) yield return (IMyInterface)obj;

Cannot implicitly convert List<T> to Collection<T>

This is a compiler error (slightly changed for readability).
This one always puzzled me. FxCop tells that this is a bad thing to return List<T> and classes that are derived from Collection<T> should be preferable as return types.
Also, FxCop says that it is OK to use List<T> for internal data storage/manipulation. Ok, I get it, but what I don't get is why the compiler complains about trying to implicitly convert List<T> to Collection<T>. Isn't List<T> more interface-charged and functional? Why prohibit implicit conversion?
And another question that stems from above: is the new List<int>(some collection<int>) constructor expensive?
Why not just do the following:
Collection<string> collection = new Collection<string>(theList);
as Collection(IList input) takes a List as part of construction.
List<T> doesn't derive from Collection<T> - it does, however, implement ICollection<T>. That would be a better choice of return type.
As for the new List<int>(some collection<int>) question - it partly depends on what the collection is. If it implements ICollection<T> (at execution time) then the constructor can use its Count property to create the list with the right initial capacity before iterating through it and adding each item. If it doesn't implement ICollection<T> then it's just equivalent to:
List<int> list = new List<int>();
foreach (int x in otherCollection)
{
list.Add(x);
}
Still nice to have in a convenient constructor, but not hugely efficient - it can't be, really.
I don't believe the constructor does anything cunning for arrays, which it potentially could - using Array.Copy or whatever to just copy the lot in one go rather than iterating though. (Likewise if it were another List<T> it could get at the backing array and copy that directly.)
List<T> doesn't inherit from Collection<T>. Plain and simple. Unless List<T> provides an operator to implicitly convert to/from Collection<T>, you can't do it. I would actually suggest returning List<T> if you can, as I believe the rules go something like this:
Accept as a parameter the least constrictive interface possible.
Return as a return parameter the most constrictive type possible.
Here is a generic extension method written in C# 3.0 used to convert List<T> to Collection<T>
using System.Collections.Generic;
using System.Collections.ObjectModel;
public static class ExtensionMethods
{
public static Collection<T> ToCollection<T>(this List<T> items)
{
Collection<T> collection = new Collection<T>();
for (int i = 0; i < items.Count; i++)
{
collection.Add(items[i]);
}
return collection;
}
}
and it is used like this…
List<string> entities = new List<string>();
entities.Add("Value 1");
entities.Add("Value 2");
entities.Add("Value 3");
entities.Add("Value 4");
Collection<string> convertedEntities = entities.ToCollection<string>();
This is how you convert from List<T> to Collection<T> (while using LINQ):
The old function:
public List<Employee> GetEmployee(int id)
{
return ( from e in MyDataContext.Employees
select new Employee()
{
e.empId = id
}
).ToList();
}
After conversion:
using System.Collection.ObjectModel;
public Collection<Employee> GetEmployee(int id)
{
return new Collection<Employee>(
(from e in MyDataContext.Employees
select new Employee()
{
e.empId = id
}
).ToList() as IList<Employee>
);
}
You can use the the below
public class EmployeeCollection : Collection<Employee>
{
public EmployeeCollection(IList<Employee> list) : base(list)
{}
public EmployeeCollection() : base()
{}
}
Use the class like this
EmployeeCollection employeeCollection = new EmployeeCollection(list)
The other way around, it is not necessary to loop... you can make just .ToList()
ICollection<T> collection = new Collection<T>();
fill your collection using any method, and when you need the list, just do this:
List<T> list = collection.ToList();
after that you can use whatever you want with your list.
Have a good coding!

Categories