1) I read some (general) code snippet and saw some places that used IList<T> and some used IEnumerable. What is the pros to use the first over the latter?
2) is and as in c#.
I understand is does type check and as does casting.
But what is exactly casting? forcing data to some sized object? when is and as differ?
A IList[<T>] represents something that:
can be iterated
is of finite, known size
is repeatable
can be accessed randomly by index
can (optionally, checkable) be edited: reassign values, add, remove, etc
An IEnumerable, on the other hand, can only be iterated. Not all things that can be iterated are lists. For example:
static IEnumerable<int> Get() {
Random rand = new Random();
while(true) yield return rand.Next();
}
that ^^^ is an infinite sequence. It has no length, cannot be mutated, cannot be accessed by index... however, it can be iterated:
foreach(int i in Get().Take(200)) {
Console.WriteLine(i);
}
is performs a type check that returns true/false... i.e. is obj an IList? yes or no.
as performs a "try to do this" type-check; it returns null if it fails, or a typed reference (etc) if it is successful. Basically, it is an efficiency thing:
if(obj is IList) {
var list = (IList) obj;
...
}
is less efficient than:
var list = obj as IList;
if(list != null) {
...
}
they also behave differently if obj is null; is throws an exception; as returns null.
IList offers certain methods that IEnumerable doesn't. Most importantly, the ability to add to it (for more information, check out the msdn)
is compares types, returning if a certain object can be casted to a type. as actually performs that cast, returning null if it failed. Casting means converting an object of type A to an object of type B, for whatever reason.
Related
I have a value I'm getting dynamically. This is because it exists in an abstraction method I'm using to build a query from a dot-notation representation of deeply related property.
I need to know if the value contains a particular value. This is easy enough for a string, but when the object in question is a collection I can't figure how to check. I can assume it's a List in my situation, but I don't know what type of list, so I can't achieve a property casting with something like List<int>.
So where x is an object and spec is dynamic this is how I test for string:
return x.ToString()?.Contains(spec, StringComparison.InvariantCultureIgnoreCase) ?? false;
This successfully determines if it's a collection type, but I still can't call Contains on it:
if (x.GetType().Namespace == "System.Collections.Generic")
{
return x.Contains(spec); //does not work
}
Also tried:
var list = (List<dynamic>)x;
var list = (List<object>)x;
But this fails in my test scenario with List<int>
When using IEnumerable I'm trying to avoid multiple enumerations. I know I can just use LINQ's .ToList() and be done with it, but that can be a lot of unnecessary list creation. I'd like to:
check and see if the underlying type is a List, and if so return that instance, otherwise
.ToList() it and return the new List
My thought was to use something akin to:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo(IEnumerable<T> enumerable)
{
var list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}
... but it appears from the documentation that the as operator just performs a cast, which would create a new List rather than returning the underlying one, would it not?
If so, how can I retrieve the underlying list instead of creating a new one?
The as operator does not create a new list. It only checks type and perform cast if type is compatible.
The code in the post is logically correct and matches how many LINQ methods are implemented (for example see source of Enumerable.Count which casts to ICollection to see if it can skip enumeration of items).
Note that it is important to cast to correct generic version of list or maybe one of its interfaces - IList would work if you must use non-generic version. Beware of the fact that List<T> is not co/contra-variant and type must match exactly unlike in case of covariant IEnumerable<out T> where you can cast parameter to IEnumerable<TBase> if IEnumerable<TDerived> passed.
Maybe you wanted to do this:
public void Fee()
{
var list = new List<string>(); // I want to retrieve this instance in Foo
Foo(list);
}
public void Foo<T>(IEnumerable<T> enumerable)
{
List<T> list = enumerable as List<T> ?? enumerable.ToList();
// do stuff with original list
}
I am using XUnit to test for scenarios where an empty Enumerable list is expected.
I have noticed that in certain scenarios:
Assert.Empty(msgs); fails;
BUT
Assert.False(msgs.Any()); is passing.
This is a bit confusing to me as I anticipated that this was testing for the same thing.
I understand that this likely because of the differences in expected behaviour between:
Enumerable.Any() (which defines this as "Determines whether a sequence contains any elements.")
AND
The empty expected in XUnit.Empty() (which defines that this is testing for an empty Object).
However, I am not sure exactly the difference as it appeared to me to be essentially testing the same thing.
Could someone please explain the differences in what is being tested for in these two different types of Asserts?
Here is the source for Enumerable.Any (The Assert.False() just validates that this returns false.):
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) return true;
}
return false;
}
Here is the source for Assert.Empty from xUnit:
public static void Empty(IEnumerable collection)
{
Assert.GuardArgumentNotNull("collection", collection);
var enumerator = collection.GetEnumerator();
try
{
if (enumerator.MoveNext())
throw new EmptyException(collection);
}
finally
{
(enumerator as IDisposable)?.Dispose();
}
}
They seem to be using a very similar way of checking for the presence of items in the collection. I'd expect the same result from each method.
Without more details about how you are using each one, it's hard to say why you are getting different results.
msge.Any() returns true when msge is not null and have one or more element and false otherwise so probebly msge is null and Assert.Empty fails when argument is null.
With the best regards.
There is a difference between these two methods:
.Any() is an extension method which takes an IEnumerable - An object an implement the IEnumerable interface to let the code iterate through it for set operations, (like .Any() or .Where())
Assert.Empty() doesn't appear to check whether an object implements IEnumerable, but only checks against an empty set if the input data is a string or an array.
My guess then is that you're passing in an IEnumerable object, rather than an array.
To get around this you could either use Assert.False(msgs.Any()); as before, or else use something like Assert.Empty(msgs.ToArray());
Ok I have looked all around and can't find an answer. I have a method that returns an
IEnumerable<ICar>
and the calling method is storing the results of the method in
List<ICar>
but I get the following error.
System.Collections.Generic.IEnumerable<Test.Interfaces.ICar> to
System.Collections.Generic.List<Test.Interfaces.ICar>. An explicit conversion exists
(are you missing a cast?)
I looked on msdn at
IEnumerable<T> interface and List<T> class.
The following line is from msdn.
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection,
IEnumerable
I just don't understand why I can't assign
IEnumerable<ICar> to List<ICar>.
Can someone please explain this to me. What am I missing.
Not all IEnumerable<T> are List<T>. The reverse is true.
You can either try to cast to List<T> which is bad practice and could fail if it really is not a list or you can create a new list from the enumeration
new List<T>(yourEnumerable);
or using Linq
yourEnumerable.ToList();
List<ICar> implements IEnumerable<ICar> - you're correct. But that means that you can implicitly convert a List<ICar> to an IEnumerable<ICar> - not the other way around. To get around your problem, just call ToList() on the IEnumerable to convert it to a List.
An IEnumerable<T> CAN BE a List<T> but is not necessarily one. You can use LINQ's IEnumerable<T>.ToList<T>() to convert any IEnumerable<T> to List<T>
IEnumerable<T> foo = ThatMethodYouWereTalkingAbout();
List<T> bar;
if (foo is List<T>)
bar = (List<T>)foo;
} else {
bar = new List<T>(foo);
}
You can call ToList to convert your IEnumerable<Car> to a List<Car>.
IEnumerable<ICar> cars = ...;
List<ICar> list = cars.ToList(); // OK
This doesn't happen automatically because although you can try to downcast IEnumerable<Car> to List<Car>:
IEnumerable<ICar> cars = ...;
List<ICar> list = (List<ICar>)cars; // Compiles, but could fail at runtime.
there is no implicit conversion operator, so the C# compiler disallows the assignment without a cast. The downcast could fail at runtime, so it is better to use ToList in most situations.
All lists are IEnumerable, but all Innumerable are not lists. According to MSDN IEnumerable
Exposes the enumerator, which supports a simple iteration over a non-generic collection.
All IEnumerable promises you is that you can get the next element. The List promises a lot more: e.g. access by index and that it as a finite length.
This is not the case with IEnumerable. For example the below code doesn't actually create a list , indeed, you can't make a list from it. Every time you ask for a new element, it gives you one. But it only calculates it when asked. :
IEnumerable<int> Numbers() {
int i=0;
while(true) {
yield return unchecked(i++);
}
}
You want to call ToList to get a list. Note this might note terminate in a case like the one above.
We cannot assign a less derived type to a more derived type through variable assignment. Thats not type safe.
In language spec. speak, List<ICar> is not assignment compatible with IEnumerable<ICar>. But, the inverse is true. IEnumerable<ICar> is assignment compatible with List<ICar>.
It makes more sense if you visualize assignment compatability as a relation. If x <= y is true, then x >= y is not true (unless y = x). (Concretely, 2 < 3 = true so 2 > 3 is not true.)
In your case, we can assign the value of a List of cars to a variable of type IEnumerable<ICar>.
If we can represent the relationship as
List<ICar> <= IEnumerable<ICar> = true.
Then it follows that
List<ICar> >= IEnumerable<ICar> = false
It's false because the first relation we know to be true.
As the easiest way to convert the IList<T1> to IList<BaseT1>?
IList<T1>.Count() is very large number!!!
class BaseT1 { };
class T1 : BaseT1
{
static public IList<BaseT1> convert(IList<T1> p)
{
IList<BaseT1> result = new List<BaseT1>();
foreach (BaseT1 baseT1 in p)
result.Add(baseT1);
return result;
}
}
You'll get much better performance in your implementation if you specify the size of the result list when it is initalized, and call the Add method on List<T> directly:
List<BaseT1> result = new List<BaseT1>(p.Count);
that way, it isn't resizing lots of arrays when new items get added. That should yield an order-of-magnitude speedup.
Alternatively, you could code a wrapper class that implements IList<BaseT1> and takes an IList<T1> in the constructor.
linq?
var baseList = derivedList.Cast<TBase>();
Edit:
Cast returns an IEnumerable, do you need it in a List? List can be an expensive class to deal with
IList<T1>.Count() is very large number!!!
Yes, which means that no matter what syntax sugar you use, the conversion is going to require O(n) time and O(n) storage. You cannot cast the list to avoid re-creating it. If that was possible, client code could add an element of BaseT1 to the list, violating the promise that list only contains objects that are compatible with T1.
The only way to get ahead is to return an interface type that cannot change the list. Which would be IEnumerable<BaseT1> in this case. Allowing you to iterate the list, nothing else. That conversion is automatic in .NET 4.0 thanks to its support for covariance. You'll have to write a little glue code in earlier versions:
public static IEnumerable<BaseT1> enumerate(IList<T1> p) {
foreach (BaseT1 item in p) yield return item;
}