Merge two lists of classes implementing the same interface - c#

In a class, I process a list of IInterface.
I want the two possible implementations to be treated in a separate way, hence:
public List<IInterface> Process(List<IInterface> InterfaceList)
{
List<FirstImplementation> FirstList = FirstProcess(InterfaceList.OfType<FirstImplementation>.ToList());
List<SecondImplementation> SecondList = SecondProcess(InterfaceList.OfType<SecondImplementation>.ToList());
return new List<IInterface> {
FirstList,
SecondList
};
}
I would like to return a List<IInterface>, same as the input, both it turns out to be more difficult than anticipated
return new List<IInterface> {
FirstList,
SecondList
};
compiles but throws an InvalidCastException at runtime,
return new List<IInterface>.AddRange(FirstList).AddRange(SecondList);
does not even compile...
What would be the correct way to do this?

Using Linq:
return FirstList.Cast<IInterface>().Concat(SecondList.Cast<IInterface>()).ToList();
Cast<> returns an enumerable (mind linq's deferred execution) with elements cast to the target type, Concat combines two enumerables and ToList turns the result into a list (and materializes the linq query).
As #Evk kindly noticed, when there is an implicit cast from both types to the output type (as in your case, you can cast both your types to their common interface), you can skip the cast completely (though in that case you need to explicitly specify the type for concatenation), as follows:
return FirstList.Concat<IInterface>(SecondList).ToList();

Related

How Can I Retrieve the Underlying List of an IEnumerable Without Creating a New List?

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
}

Cast List<Y> to List<X> fast, without new List creation

I need to cast List with references to base type to list with references to derived type. I can't use LINQ ToList, because it creates new list and this is slow for me. Is there in C# some quick cast, maybe like in C++. Thanks.
You can't do that. And there is a reason for it. Consider the following.
List<Animal> animals = new List<Cat>();
animals.Add(new Dog());
You lose the type safety of the List<T> here, this is why List is not covariant on T. What you can do is cast it to IEnumerable<X>, because IEnumerable only supports getting an element and this is why IEnumerable is covariant on its type parameter.
You don't need to create a new list if you want to just iterate the elements, without changing anything about the list itselft.
Do you actually need a new list? Can you use LINQ OfType<T>() or Cast<T>()?
var baseList = new List<BaseType>();
var derivedItems = baseList.OfType<DerivedType>();
Have you tried:
List<Y> listY = new List<Y>()
var listX = ListY.Select(y => new X(y));
This will create an IEnumerable<X> that you can enumerate
LINQ Cast() is going to be you friend here. However, be wary: if you have anything not castable, this code is going to crash.
List<object> newList= new List<Object>();
newList.Add("SomeString");
foreach( string s in newList.Cast<string>())
{
//Do something
}
You can't cast one type to another without creating something new.
Hence, the only option you have is to create a new list, or have something that can iterate over the existing list and acts like a type of another. You could implement your own enumerator, or simply create a method returning a IEnumerable<TypeY> and yield return inside (which kind of create an enumerator).
public IEnumerable<TypeY> Convert(IEnumerable<TypeX> listX)
{
foreach (TypeX x in listX)
{
yield return ConvertXToY(x);
}
}

Cannot implicitly convert type with extension method

I have a extension method for an enum
public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
{
CheckIsEnum<T>(true);
foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
{
if (value.IsFlagSet(flag))
yield return flag;
}
}
I try to get the result like this:
Zone_Status_ZoneConditionFlagEnum flags = (Zone_Status_ZoneConditionFlagEnum)flagsRaw;
List<Zone_Status_ZoneConditionFlagEnum> ZoneConditionFlags_List = (List<Zone_Status_ZoneConditionFlagEnum>)flags.GetFlags();
But I get
NX584(NX584Test)->Error parsing message: Cannot implicitly convert type [Digicom.NX584Engine.Messages.Zone_Status_ZoneConditionFlagEnum] to System.Collections.Generic.List`1[Digicom.NX584Engine.Messages.Zone_Status_ZoneConditionFlagEnum].
It's not clear to me why you're getting that error - but you can't cast the result of GetFlags<T> to a List<T>, because it doesn't return a List<T>. The simplest fix would be:
var ZoneConditionFlags_List = flags.GetFlags().ToList();
If that doesn't work, please give the new error message.
Alternatively, you could change GetFlags so it actually returned a List<T> rather than using an iterator block.
The first issue here is that a sequence is different to a list; if you need a list, either return a list, or add .ToList() after GetFlags(), i.e.
var ZoneConditionFlags_List = flags.GetFlags().ToList();
However, the bigger problem is that you can't use that IsFlagSet in that generic context; that method is not defined for an arbitrary T : struct.
Personally, I think you'd be better just to treat it as a [Flags] enum throughout; I assume you have existing code that wants a list rather than a single value?
GetFlags returns an IEnumerable<T>, not a List<T>, you cannot cast here.
You should, however, be able to construct a list from the results:
List<Zone_Status_ZoneConditionFlagEnum> ZoneConditionFlags_List = flags.GetFlags().ToList();
However, the error does not match the code here exactly, it should complain about an IEnumerable not be able to be cast, but instead it says the enum type. Are you sure this is the right code?

IEnumerable<T> to List<T>

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.

Why use IList over IEnumerable?

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.

Categories