Convert System.Linq.IOrderedEnumerable<T> to List<T> - c#

.NET compiler will not implicitly convert System.Linq.IOrderedEnumerable<T> to System.Collections.Generic.List<T>
An explicit cast:
using System.Collections.Generic;
var items = new List<MyType>;
var selectedItems =
from item in items
where item.Active
select item;
return (List<MyType>)selectedItems;
gives this warning:
Suspicious cast: there is no type in the solution which inherits from
both System.Linq.IOrderedEnumerable and
System.Collections.Generic.List
What is best practice here?

Simply use the ToList extension:
return selectedItems.ToList();
You should be aware though: best practice (since you asked) would actually want you to return an IEnumerable<MyType> in most cases. Therefore, you may want to change your signature in this way:
public IEnumerable<MyType> MyFunction()
{
// your code here
}
And THEN, if you need to, have the function's result in a list:
var myList = MyFunction().ToList();
Unless you have a very precise reason of returning a List<> type, I strongly suggest that you don't.
Hope that helps.

Use the System.Linq.Enumerable.ToList<T>() extension:
selectedItems.ToList();

Related

List to IEnumerable in a Async method

I have a method:
public Task<IEnumerable<MyDetails>> HandleAsync(...)
Within this method, I simply build a list of items.
IEnumerable<MyDetails> myDetails = new List<MyDetails> {
new MyDetails{ Name = 'John' },
new MyDetails{ Name = 'James' },
new MyDetails{ Name = 'Anne' },
};
And then return the result.
return Task.FromResult(insuraceTypeDetails);
In a code review, I'm being asked to use var instead of IEnumerable<MyDetails>
However, when attempting that, I get an error on my return:
Cannot convert type Threading.Tasks.Task<List> to
Threading.Tasks.Task<IEnumerable>
I thought this would be fine, but the compiler will not allow it. Can I use var here? Or am I correctly explicitly telling the compiler what we need?
In a code review, I'm being asked to use var instead of IEnumerable<MyDetails>
var will infer the type the variable from the intialization, in this cast a List<MyDetails>. But as you have discovered, you need the variable to be an IEnumerable<MyDetails> to match the return type.
You could do something goofy like convert it to an IEnumerable:
return Task.FromResult(insuraceTypeDetails.AsEnumerable());
or do an explicit cast:
return Task.FromResult((IEnumbrable<MyDetails>)insuraceTypeDetails);
but those are just working around a dogmatic coding style. There's absolutely nothing wrong with explicitly declaring the variable type, especially when using the inferred type does not work.
Use IEnumerable<MyDetails> and explain to your colleagues why var is not the right choice here.

return a List< Id:int, Name:string>

I am having a function which return a list of type: List< Id:Name, Name:string >
how do you do specify in C# to return this List Type ?
Here is the code:
public ?????? GetDepartements( int idRegion )
{
var a = (from o in _meilleurPrestaEntities.Departements
where o.de_id_region == idRegion
select new {Id = o.id_departement, Name = o.nom}).ToList();
return a;
}
the return is used as Json result.
thanks
I'd suggest using a key value pair
return List<KeyValuePair<int,string>>()
[Edit] You'll need to modify your code slightly - it should look something like this:
var a = (from o in _meilleurPrestaEntities.Departements
where o.de_id_region == idRegion
select new KeyValuePair<int,string>(o.id_departement,o.nom}).ToList();
You can't. You have a list of anonymous type and you can't specify anonymous type as part of a method return type (or pretty much anywhere else, unless you can use var).
To fix this, you have several options:
Create normal class to represent the return type and use that in your return type.
Use something like List<Tuple<int, string>>.
Return List<dynamic>. This way, you will be able to treat the returned value as usual, but you will get no compile-time checking or IntelliSense.
Return List<object>. This can be useful if you don't need to access the properties in the usual way, but you will only pass the result to something that uses reflection.
I think you have to specify a type and then use that type for your return value and in your select statement.
I don't have VisualStudio open to try it, but I think you can actually return dynamic in this case. Or you could use ExpandoObject.
However, as others have mentioned, the "better" way is to use something like Tuple or KeyValuePair, or don't be lazy and just make an actual model for what you will return to the view (in other words, a "View Model").

LINQ query on object with unknown class

I have an array of unknown (to the current method) class objects. I do know that each class has a property called "Number".
I am trying to write a LINQ query where I am looking for the object with the next Number in sequence. AKA, I'm at Number 8, use a LINQ query to find the object where Number=9.
Anyone got a suggestion?
Also, I use reflection often so don't worry about avoiding it.
You can create an interface - INumber with a property Number. Each of the objects that you are having in the array can implemen this interface.
That way, you will have an array of known type INumber. This way your query will be easy to debug and maintain.
If the objects all inherit from a known interface then you can cast them, e.g.
var next = items.Cast<IHasNumber>.FirstOrDefault(x => x.Number == index + 1);
If they don't, then you can use dynamic, e.g.
var next = items.Cast<dynamic>.FirstOrDefault(x => x.Number == index + 1);
If you have control of the types, then I would make them implement an interface so that you can use the first method, which should be significantly faster than the second. In that case, your collection will probably be IEnumerable<IHasNumber> to start with and you won't even have to cast.
If as you indicated elsewhere that you designed all the classes then you could put that number property in an in interface and have all the classes implement that interface. Then, in the linq query, use the interface.
If you truly do not have a common type that you can reduce to and for some reason cannot introduce such a type, then you may be able to use the dynamic keyword. I don't have access to a compiler at the moment, but can your method accept a collection of dynamic objects and query them?
For example:
IEnumerable<dynamic> collection = ...;
var numbers = from x in collection
select x.Number;
To avoid performance issues you can use the following method:
static void Main(string[] args)
{
object[] objs = GetInitialData();
var accessor = GetGetterHelper<int>(objs[0].GetType(), "Number");
var res = from a in objs where accessor(a) == 7 select a;
}
static Func<object, T> GetGetterHelper<T>(Type type, string methodName)
{
var methodInfo = type.GetProperty(methodName).GetGetMethod();
return x => (T)methodInfo.Invoke(x, new object[] {});
}

C# Generics: How can I use them generically?

[TestMethod]
public void TestMyGenericBaseClasses()
{
Type typeCrazy = ThisPartyIsTypeCrazyWOOT();
// How do I create a generic object?
MadnessOhYeah<typeCrazy> sanity = new MadnessOhYeah<typeCrazy>();
// How do I use a generic object after it has been created?
Assert.IsTrue(sanity.MyTrueFunction(), "this is sparta");
// How do I call a generic function generically?
bool result = MyFunction<typeCrazy>();
Assert.IsTrue(result, "I did not get my teeth whitened!");
}
Is there any way to make this compile? (ThisPartyIsTypeCrazyWOOT returns a Type) Because this is a test, we're not concerned about having to use reflection or anything, unless that's just absolutely crazy.
I'm getting the vibe that this isn't going to be possible though, and that our test functions will just have to be more specific.
You need Type.MakeGenericType Method. Then Activator.CreateInstance Method.
Update 2: The first example I posted still doesn't 100% answer the question, since it involves a cast to List<int>, which is a type that is known at compile time. Below is a reflection-only solution that illustrates how you can use a generic type knowing nothing about the type argument itself. But, as you can see, it's... well, disgusting ;)
Type userType = GetUserSuppliedType();
// Now let's say userType is T.
// Then here we are getting the type typeof(List<T>).
// But, of course, there's no way to have any such information in the code.
Type listOfUserType = typeof(List<>).MakeGenericType(new[] { userType });
// This is effectively calling new List<T>();
object listObject = Activator.CreateInstance(listOfUserType);
// Do you see how messy this is getting?
MethodInfo addMethod = listOfUserType.GetMethod("Add");
// We better hope this matches userType!
object input = GetUserSuppliedInput();
// I suppose we could check it, to be sure...
if (input == null || input.GetType() != userType)
{
throw new InvalidOperationException("That isn't going to work!");
}
// Here we are finally calling List<T>.Add(input) -- just in the most ass-
// backwards way imaginable.
addMethod.Invoke(listObject, new[] { input });
Update: OK, if you insist on doing this, here's an example of how it's possible—but very cumbersome!
Type genericListType = typeof(List<>);
Type listOfInt32Type = genericListType.MakeGenericType(new[] { typeof(int) });
object listObject = Activator.CreateInstance(listOfInt32Type);
List<int> list = (List<int>)listObject;
list.Add(1);
Generics can't quite work like this because a Type object could be anything. Consider this code:
var list = new List<int>();
list.Add(1);
The type of list in the above code is known to be List<int>, which defines what operations are legal on list such as Add(1).
Now consider this instead:
Type t = GetTypeFromIndeterminateSourceSuchAsUserInput();
var list = new List<t>();
list.Add(?);
When t is a Type object rather than the name of a type (like int) which the compiler can parse, it's not really possible to instantiate a generic type using that type—or rather, it's possible (see Andrey's answer), but you can't really use the resulting object in any sort of generic way.
Now, you might think that something like this ought to work:
Type t = typeof(int);
var list = new List<t>();
list.Add(1);
...but just because the value of t is known (by you) at compile time doesn't change the way things work in general.
Anyway, yes it's possible using reflection; but if you go down that path, you're committing to a pretty reflection-heavy solution. What I'm getting at is that in general it isn't a particularly realistic thing to do.

How to cast list to enumerable

I've got a problem with the following code:
public IEnumerable<ISession> GetSessions()
{
// ...
using (ProvaDbEntities DBEntities = new ProvaDbEntities(Utilities.ToEntitiesConnectionString()))
{
ObjectQuery<session> sessions = DBEntities.session;
IEnumerable<session> q1 = from session in sessions
where session.site == this.Name
select session;
List<Session> sessionList = new List<Session>();
foreach (var s in q1)
{
sessionList.Add(new Session(s.id.ToString(),s.username, s.site, new DateTime()));
}
IEnumerable<Session> res = sessionList;
return sessionList;
}
}
The exception is:
Is not possible to cast object type 'System.Collections.Generic.List`1[prova3.Session]' to type 'System.Collections.Generic.IEnumerable`1[TAP2009.AuctionSite.Interfaces.ISession]'.
Looking at this SO question it seems to be correct. Am I wrong?
It should be fine, so long as Session implements ISession - if you're using C# 4 and .NET 4. If you're not, it won't be.
Note that the question you referred to use the same "T" in both cases - whereas the exception you've got is about converting a List<Session> to an IEnumerable<ISession>. You haven't stated where you're getting the exception, which makes it a bit harder to see exactly what's going on... Are you sure this is actually the code which is failing? Are you sure you're getting an exception rather than a compile-time failure?
EDIT: If you're not using .NET 4 and C# 4, the workaround for covariance is reasonably simple here - use the Cast<T>() LINQ operator:
return sessionList.Cast<ISession>();
Have you tried using the extension method AsEnumerable()?
So this line
IEnumerable<Session> res = sessionList;
Would change to
IEnumerable<Session> res = sessionList.AsEnumerable();
The return type is public IEnumerable<ISession>, i forgot to specify the type of the Ienumerable..
You can add using System.Linq and use the extension method Cast<T> that returns a IEnumerable<T>.

Categories

Resources