List not inheriting an IEnumerable extension method - c#

I have the following code that creates an extension to an IEnumerable<T>:
//http://stackoverflow.com/a/1779135/1180926
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int n)
{
//.......
}
When I try to apply this to a list:
public static void RemoveTwo(List<string> strList)
{
strList = strList.SkipLast(2);
}
I get the following error:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to
'System.Collections.Generic.List'. An explicit conversion
exists (are you missing a cast?)
But List<T> inherits IEnumerable<T> (src), so shouldn't it also inherit its extension methods?

You have to create a list from the IEnumerable<string>:
public static void RemoveTwo(List<string> strList)
{
strList = strList.SkipLast(2).ToList();
}
Your extension returns IEnumerable<string> which is not a List<string>. However, if you want to modify strList you have to use methods of Lists like Remove that modify the original collection or you have to return the new list.
Instead of SkipLast you should use RemoveAt if you want to change the original collection without returning a new list.
public static void RemoveTwo(List<string> strList)
{
if(strList.Count > 0)
strList.RemoveAt(strList.Count-1);
if(strList.Count > 0)
strList.RemoveAt(strList.Count-1);
}

What you're doing wrong is assigning back to the list the IEnumerable<string> return value. You can't do that, as even though all List<T>s are also IEnumerable<T>, the reverse is not true. What you need to do is add a ToList() at the end of the SkipLast call:
public static List<string> RemoveTwo(List<string> strList)
{
return strList.SkipLast(2).ToList();
}

Your issue lies not in the invocation of the extension method (which works as is), but in the assignment of its IEnumerable<string> return value to a List<string> variable. For the sake of demonstrating, the following code would work compile fine (but do nothing):
public static void RemoveTwo(List<string> strList)
{
strList.SkipLast(2);
}

Related

IEnumerable<IEnumerable>> and Extension Method

I was wondering if someone could help me understand the following behavior. In the following code, I am creating a CustomObject instance, which contains a single Property of type IEnumerable<IEnunumerable>>.
I also have an extension Method on IEnumerable<T> called AsDataTable.
public class CustomObject
{
public IEnumerable<IEnumerable> Collection {get;set;}
}
public static class ExtensionMethods
{
public static bool AsDataTable<T>(this IEnumerable<T> list)
{
Console.Write("In extension method");
return default(bool);
}
}
void Main()
{
var ttObject = new CustomObject()
{
Collection = new List<IEnumerable>
{
new List<int>{1,2,3},
new [] {new{A="abc",B="def"}}
}
};
var dummy = new []{new {a='r'}}.AsDataTable();
foreach(var item in ttObject.Collection)
{
var temp = item.AsDataTable();
Console.WriteLine($"Item is IEnumerable : {item is IEnumerable}");
}
}
What makes me wonder if the following line of code works (or rather compiles)
var dummy = new []{new {a='r',b='3'}}.AsDataTable();
while when I loop over the Collection Property of CustomObject and then do the same it doesn't allow me to compile.
var temp = item.AsDataTable(); // this doesn't work
Curiously the following line returns true reconfirming 'item' is indeed IEnumerable.
Console.WriteLine($"Item is IEnumerable : {item is IEnumerable}");
I guess it is because the extension method is written over Generic version IEnumerable<T>, but then how is it that it works over the anonymous type array (outside the CustomObject).
IEnumerable<T> implements IEnumerable, not vice versa.
Through a bit of runtime hacking, SomeType[] actually does implement IEnumerable<SomeType>. On the other hand, IEnumerable doesn't - and overload resolution is done at compile time, so the compiler has no idea that your IEnumerable items in the collection actually also implement IEnumerable<int>.
If you need to work with IEnumerable, you need to use that in your extension method.

List instance does not recognized in method context in C#

I am trying to understand why compiler throws an error when I try to use "List" specific method "Add" in this context. The error explanation states that it is because of the field definition. (IEnumerable does not include "Add" method) However, I newed it in inner context. I will be grateful for a reasonable explanation.
Note: I know that is because IEnumerable is an interface and I can use IList instead. However, what I could not understand is that compiler should extract the type in inner context but its not.
class Program
{
private static IEnumerable<string> exampleList;
public static void Main()
{
exampleList = new List<string>();
exampleList.Add("ex"); // ==> Compiler Error Here.
}
}
Your exampleList is defined as an IEnumerable<string>, so its compile-time type is an IEnumerable<string>. Therefore, when the compiler is compiling the code, it can only know that it is an IEnumerable<string>.
Two main fixes exist:
1) Declare exampleList as an IList
private static IList<string> exampleList;
2) Use a temporary variable to set the list contents.
public static void Main()
{
var list = new List<string>();
list.Add("ex");
exampleList = list;
}
Just to briefly explain why the compiler can only know that it is an IEnumerable, consider the following code:
IEnumerable<string> exampleList;
if (TodayIsAWednesday())
{
exampleList = new List<string>();
}
else
{
exampleList = new string[0];
}
// How can the compiler know that exampleList is a List<string>?
// It can't!
exampleList.Add("ex");
Change your code as below, will solve the problem.
private static List<string> exampleList;
or change your code in static Main as below
var newCollection = exampleList.ToList();
newCollection.Add("ex"); //is your new collection with the item added
As you see,"I" meant it is a Interface.It can accept all kind of Enumerable,but have not Add's Method.
You can see:https://msdn.microsoft.com/en-us//library/system.collections.ienumerable(v=vs.110).aspx

How to create a List<long> from a long variable?

how can i convert a long variable into the list?
Code:
long taskId = long.Parse(LocalWorkListVM.ActiveTask.TaskId, CultureInfo.InvariantCulture);
I need to convert it into a List<long> because one of our method expect a list to pass.
So you need a List<long> but you only have a single variable. That's easy, you can use the collection initializer syntax:
List<long> longs = new List<long>{ taskId };
or more verbose with List.Add:
List<long> longs = new List<long>();
longs.Add( taskId );
Try this:
List<long> somelist = new List<long>{long.Parse(LocalWorkListVM.ActiveTask.TaskId, CultureInfo.InvariantCulture)};
This will create a new List and initialise it with the parsed value.
Does it really need to be a List? If there is a way to modify that method to accept an IEnumerable things would get much easier and cleaner (or if IEnumerable is not enough, maybe consider IList).
So considering this, you have a bunch of options.
You can use the Enumerable class' static method Repeat:
Enumerable.Repeat(taskId, 1);
You can write your own extension method:
static class IEnumerableExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this T item)
{
yield return item;
}
}
// and use it as:
taskId.ToEnumerable()
Of course this extension method can be modified to return a List or IList or whatever your exact needs are.
Also, you might create a new overload of the function, which expects a single long instead of the List, somewhere along the lines of this:
public void MyMethod(List<long> list)
{
// Do something
}
public void MyMethod(long item)
{
MyMethod(new List<long>{ item });
}
And finally, there is a nice keyword called params:
public void MyMethod(params long[] items)
{
// call to the previously mentioned extension method
MyMethod(items.ToEnumerable());
}
public void MyMethod(IEnumerable<long> items)
{
// Do stuff
}
This solution has the advantage to work with a single long parameter, comma separated long parameters or with an IEnumerable<long>.

C# ICollection extension

I would like to write a C# extension for generic Array but it's always casting an Error. Here is the code i used to create extendsion for string[] which works well :
public static string[] Add(this string[] list, string s, bool checkUnique = false, bool checkNull = true){
if (checkNull && string.IsNullOrEmpty(s)) return list;
if (checkUnique && list.IndexOf(s) != -1) return list;
ArrayList arr = new ArrayList();
arr.AddRange(list);
arr.Add(s);
return (string[])arr.ToArray(typeof(string));
}
What i really want is do it more generic so it will also works for other types not only string (so i tried to replace all string specifics with generics T) :
public static T[] Add(this T[] list, T item, bool checkUnique = false){
if (checkUnique && list.IndexOf(item) != -1) return list;
ArrayList arr = new ArrayList();
arr.AddRange(list);
arr.Add(item);
return (T[])arr.ToArray(typeof(T));
}
but the code won't compile. It's casting an error "error CS0246: The type or namespace name `T' could not be found. Are you missing a using directive or an assembly reference?"
I already tried another solution around :
public static void AddIfNotExists<T>(this ICollection<T> coll, T item) {
if (!coll.Contains(item))
coll.Add(item);
}
but it's casting another error "error CS0308: The non-generic type `System.Collections.ICollection' cannot be used with the type arguments"
As a side note, I'm using Unity C# (which is compiles against 3.5 I think). Can anyone help me ?
Your last method does not compile because of the missing reference to the System.Collections.Generic namespace. You seem to have included the reference to System.Collections only.
You could just use LINQ and make your method a bit simpler:
public static T[] Add<T>(this T[] list, T item, bool checkUnique = false)
{
var tail = new [] { item, };
var result = checkUnique ? list.Union(tail) : list.Concat(tail);
return result.ToArray();
}
You can change the method signature to this:
public static T[] Add<T>(this T[] list, T item, bool checkUnique = false)
{}
However, there are no generic methods for T[] so list.IndexOf(item) won't compile.
Your last code should work IF you are NOT calling it for string arrays, as arrays have fixed sizes!
The following exampl works for me with your extension method that uses ICollection:
List<string> arr = new List<string>();
arr.AddIfNotExists("a");

Using a class derived from generic list with LINQ

I have two classes, CheckboxItemsList which extends a generic list, and CheckboxItems, which contains a list of objects of type CheckboxItem.
I want to use LINQ to be able to filter CheckboxItemsList based on properties of its CheckboxItems objects. The return type is always a generic list, though, but I want it to be a CheckboxItemsList.
So I guess the basic question is, can linq be made to return a list of the same type that it starts with? Since I can't cast a base class to a derived class, do I have any option other than iterating through the results of the linq query and rebuilding the derived list object row by row? Not that this is the end of the world, but I'm relatively new to linq and was wondering it there is a better way to do it.
What I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
(obviously doesn't work since the query will return List<CheckboxItems>, not CheckboxItemsList)
The objects, generally:
public class CheckboxItemsList: List<CheckboxItems>
{
// does not add any fields, just access methods
}
public class CheckboxItems : IEnumerable<CheckboxItem>
{
public long PrimaryKey=0;
protected CheckboxItem[] InnerList;
public bool Changed
{
get {
return (InnerList.Any(item => item.Changed));
}
}
....
}
No, this is not possible out of the box. You'll need to add code to do this.
For example, you can add a constructor like so:
public CheckboxItemsList(IEnumerable<CheckboxItems> checkboxItems) {
// something happens
}
Then you can say
CheckboxItemsList newList = new CheckboxItemsList(
MyCheckboxItemsList.Where(item => item.Changed)
);
Additionally, you could add an extension method like so
static class IEnumerableCheckboxItemsExtensions {
public static ToCheckboxItemsList(
this IEnumerable<CheckboxItems> checkboxItems
) {
return new CheckboxItemsList(checkboxItems);
}
}
and then
CheckboxItemsList newList =
MyCheckboxItemsList.Where(item => item.Changed)
.ToCheckboxItemsList();
LINQ works on IEnumerable<T> and IQueryable<T> and the result types of all LINQ operations (Where, Select) etc, will return one of those. The standard ToList function returns a concrete list of type List<T>, you may need to come up with an extension method, e.g.:
public static CheckboxItemsList ToItemList(this IEnumerable<CheckboxItem> enumerable)
{
return new CheckboxItemsList(enumerable);
}
No, there's no built-in way to do this. You have two main options:
Add a constructor to your CheckboxItemsList class that takes an IEnumerable<CheckboxItems> or similar. Pass that collection on to the base List<T> constructor that takes an IEnumerable<T>. That base constructor should then populate the list for you:
var newList =
new CheckboxItemsList(MyCheckboxItemsList.Where(item=>item.Changed));
// ...
public class CheckboxItemsList : List<CheckboxItems>
{
public CheckboxItemsList(IEnumerable<CheckboxItems> collection)
: base(collection)
{
}
}
Create an extension method that takes an IEnumerable<CheckboxItems> or similar and returns a populated CheckboxItemsList:
var newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToCheckboxItemsList();
// ...
public static class EnumerableExtensions
{
public static CheckboxItemsList ToCheckboxItemsList(
this IEnumerable<CheckboxItems> source)
{
var list = new CheckboxItemsList();
foreach (T item in source)
{
list.Add(item);
}
return list;
}
}
(Of course, for completeness you could implement both of these options. The extension method would then just pass its IEnumerable<CheckboxItems> argument on to the constructor rather than manually looping and adding each item.)
You can also use "Conversion Operator", as below:
public class CheckboxItemsList: List<CheckboxItems>
{
public static implicit operator CheckboxItems(IEnumerable<CheckboxItems> items)
{
var list = new CheckboxItemsList();
foreach (var item in items)
{
list.Add(item);
}
return list;
}
}
Now, the below code would work.
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed);
From MSDN:
A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. This is described further in Section 6.1.
A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. Explicit conversions can occur in cast expressions, and are described further in Section 6.2.
Here is what I came up with, building on the various suggestions of others. A generic extension method:
public static T ToList<T>(this IEnumerable baseList) where T : IList,new()
{
T newList = new T();
foreach (object obj in baseList)
{
newList.Add(obj);
}
return (newList);
}
So now I can do what I want:
CheckboxItemsList newList = MyCheckboxItemsList.Where(item=>item.Changed)
.ToList<CheckboxItemsList>();
Another pretty obvious solution occurred to me, which is also useful for situations where the derived list class has field properties that I need to maintain in the new list.
Just create a new instance of my derived list class, and use AddRange to populate it.
// When created with a CheckboxItemsList parameter, it creates a new empty
// list but copies fields
CheckboxItemsList newList = new CheckboxItemsList(OriginalList);
newList.AddRange(OriginalList.Where(item => item.Changed));

Categories

Resources