IEnumerable<IEnumerable>> and Extension Method - c#

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.

Related

Why can I initialize a List like an array in C#?

Today I was surprised to find that in C# I can do:
List<int> a = new List<int> { 1, 2, 3 };
Why can I do this? What constructor is called? How can I do this with my own classes? I know that this is the way to initialize arrays but arrays are language items and Lists are simple objects ...
This is part of the collection initializer syntax in .NET. You can use this syntax on any collection you create as long as:
It implements IEnumerable (preferably IEnumerable<T>)
It has a method named Add(...)
What happens is the default constructor is called, and then Add(...) is called for each member of the initializer.
Thus, these two blocks are roughly identical:
List<int> a = new List<int> { 1, 2, 3 };
And
List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;
You can call an alternate constructor if you want, for example to prevent over-sizing the List<T> during growing, etc:
// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }
Note that the Add() method need not take a single item, for example the Add() method for Dictionary<TKey, TValue> takes two items:
var grades = new Dictionary<string, int>
{
{ "Suzy", 100 },
{ "David", 98 },
{ "Karen", 73 }
};
Is roughly identical to:
var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;
So, to add this to your own class, all you need do, as mentioned, is implement IEnumerable (again, preferably IEnumerable<T>) and create one or more Add() methods:
public class SomeCollection<T> : IEnumerable<T>
{
// implement Add() methods appropriate for your collection
public void Add(T item)
{
// your add logic
}
// implement your enumerators for IEnumerable<T> (and IEnumerable)
public IEnumerator<T> GetEnumerator()
{
// your implementation
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Then you can use it just like the BCL collections do:
public class MyProgram
{
private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };
// ...
}
(For more information, see the MSDN)
It is so called syntactic sugar.
List<T> is the "simple" class, but compiler gives a special treatment to it in order to make your life easier.
This one is so called collection initializer. You need to implement IEnumerable<T> and Add method.
According to the C# Version 3.0 Specification "The collection object to which a collection initializer is applied must be of a type that implements System.Collections.Generic.ICollection for exactly one T."
However, this information appears to be inaccurate as of this writing; see Eric Lippert's clarification in the comments below.
It works thanks to collection initializers which basically require the collection to implement an Add method and that will do the work for you.
Another cool thing about collection initializers is that you can have multiple overloads of Add method and you can call them all in the same initializer! For example this works:
public class MyCollection<T> : IEnumerable<T>
{
public void Add(T item, int number)
{
}
public void Add(T item, string text)
{
}
public bool Add(T item) //return type could be anything
{
}
}
var myCollection = new MyCollection<bool>
{
true,
{ false, 0 },
{ true, "" },
false
};
It calls the correct overloads. Also, it looks for just the method with name Add, the return type could be anything.
The array like syntax is being turned in a series of Add() calls.
To see this in a much more interesting example, consider the following code in which I do two interesting things that sound first illegal in C#, 1) setting a readonly property, 2) setting a list with a array like initializer.
public class MyClass
{
public MyClass()
{
_list = new List<string>();
}
private IList<string> _list;
public IList<string> MyList
{
get
{
return _list;
}
}
}
//In some other method
var sample = new MyClass
{
MyList = {"a", "b"}
};
This code will work perfectly, although 1) MyList is readonly and 2) I set a list with array initializer.
The reason why this works, is because in code that is part of an object intializer the compiler always turns any {} like syntax to a series of Add() calls which are perfectly legal even on a readonly field.

Casting an object to a base collection

I'm not totally convinced this is possible, but here goes. I have a method returning an object, although the actual type is Collection. Now, I can easily cast the object into the collection using
var myCollection = myObject as Collection<MyClassA>;
However the problem I have is that Collection<MyClassA> could alternatively be Collection<MyClassB> or Collection<MyClassC>. All of these MyClassX's are inherited from MyBaseClass, so ideally I would like to be able to do something like
var myCollection = myObject as Collection<MyBaseClass>;
However this throws an exception when casting. Is it possible to do this in anyway? I understand that it may be within .Net 4?
Thanks for the help.
EDIT:
OK - The answers so far are very useful, however they only solve the second part of the solution - converting/casting collections.
I am still unsure as to how I should initially cast the object to a collection (without the use of a huge if statement for each of the possible types)
This is only supported with IEnumerable<T> in .NET 4. Check out the difference in the signatures:
IEnumerable<T>:
public interface IEnumerable<out T> : IEnumerable
Collection<T>:
public class Collection<T> : IList<T>,
ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
That out keyword in the type parameter is what tells .NET to support variance.
Before I had access to .NET 4 I wrote an extension method that achieved this:
public static IEnumerable<U> CastCollection<T, U>(this IList<T> items) where U : class
{
var collection = new List<U>();
foreach (var item in items)
{
if (item is U)
{
var newItem = item as U;
collection.Add(newItem);
}
}
return collection;
}
You would use it like this:
var myCollection = myObject.CastCollection<MyClassA, MyBaseClass>();
myCollection will be an IEnumerable<MyBaseClass> in this case.
Alternate solution: you could use interfaces and generics to get what you want.
public interface IMyClass
{
}
public class MyClassA : IMyClass
{
}
public class MyClassB : IMyClass
{
}
public class MyClassC : IMyClass
{
}
static void Main(string[] args)
{
var listA = new List<IMyClass>{new MyClassA{}, new MyClassA{}};
var listB = new List<IMyClass> { new MyClassB { }, new MyClassB { } };
var listC = new List<IMyClass> { new MyClassC { }, new MyClassC { } };
List<IMyClass> genericList = listA.Cast<IMyClass>().ToList();
}
Something like this will compile properly and also allow you to assign different lists of any types that implement the common interface, to the same variable (in this case genericList.
This cannot be done by casting the collection as a whole. However, you can cast the individual elements to a new collection. Look at LINQ's Cast<> extension method.

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));

C# Generic overloading of List<T> : How would this be done?

The StringBuilder class allows you, in what I consider to be a very intuitive way, to chain method calls to .Append(), .AppendFormat() and some others like so:
StringBuilder sb = new StringBuilder();
sb.Append("first string")
.Append("second string);
The List class' .Add() method, on the other hand, returns void - so chaining calls doesn't work. This, in my opinion and the immortal words of Jayne Cobb "just don' make no kinda sense".
I admit that my understanding of Generics is very basic, but I would like to overload the .Add() method (and others) so that they return the original object, and allow chaining. Any and all assistance will be rewarded with further Firefly quotes.
If you want to keep the same name for the Add method, you could hide the method from the base class:
public class MyList<T> : List<T>
{
public new MyList<T> Add(T item)
{
base.Add(item);
return this;
}
}
However, this will only work if you're manipulating the list with a variable explicitly typed as MyList<T> (i.e. it won't work if your variable is declared as IList<T> for instance). So I think the solutions involving an extension method are better, even if that means changing the name of the method.
Although others have already posted solutions with extension methods, here's another one, that has the advantage of conserving the actual type of the collection:
public static class ExtensionMethods
{
public static TCollection Append<TCollection, TItem>(this TCollection collection, TItem item)
where TCollection : ICollection<TItem>
{
collection.Add(item);
return collection;
}
}
Use it like that:
var list = new List<string>();
list.Append("Hello").Append("World");
use can create extension method
public static class ListExtensions
{
public static List<T> AddItem<T>(this List<T> self, T item)
{
self.Add(item);
return self;
}
}
var l = new List<int>();
l.AddItem(1).AddItem(2);
EDIT
we can also make this method generic over collection parameter
public static class ListExtensions
{
public static TC AddItem<TC, T>(this TC self, T item)
where TC : ICollection<T>
{
self.Add(item);
return self;
}
}
var c1 = new Collection<int>();
c1.AddItem(1).AddItem(2);
var c2 = new List<int>();
c2.AddItem(10).AddItem(20);
EDIT 2:
Maybe someone will find this trick useful, it is possible to utilize nested object initializer and collection initializer for setting properties and adding values into existing instances.
using System;
using System.Collections.Generic;
using System.Linq;
struct I<T>
{
public readonly T V;
public I(T v)
{
V = v;
}
}
class Obj
{
public int A { get; set; }
public string B { get; set; }
public override string ToString()
{
return string.Format("A={0}, B={1}", A, B);
}
}
class Program
{
static void Main()
{
var list = new List<int> { 100 };
new I<List<int>>(list)
{
V = { 1, 2, 3, 4, 5, 6 }
};
Console.WriteLine(string.Join(" ", list.Select(x => x.ToString()).ToArray())); // 100 1 2 3 4 5 6
var obj = new Obj { A = 10, B = "!!!" };
Console.WriteLine(obj); // A=10, B=!!!
new I<Obj>(obj)
{
V = { B = "Changed!" }
};
Console.WriteLine(obj); // A=10, B=Changed!
}
}
public static IList<T> Anything-not-Add*<T>(this IList<T> list, T item)
{
list.Add(item);
return list;
}
* AddItem, Append, AppendList, etc. (see comments below)
The same idea came to my mind like other guys' too, independently:
public static TList Anything<TList, TItem>(this TList list, TItem item)
where TList : IList<TItem>
{
list.Add(item);
return list;
}
And Thomas is right: as far as IList<T> inherits ICollection<T> you should use ICollection.
Have an extension method off:
public static List<T> Append(this List<T> list, T item)
{
list.Add(item);
return self;
}
Note that we have to create it with a new name, as if an instance member matches the signature (the 'Add' you are already complaining about) then the extension method won't be called.
In all though, I'd recommend against this. While I like chaining myself, it's being rare in C# libraries means it's not as idiomatic as it is in other languages where it's more common (no technical reason for this, though some differences in how properties work encourages it a bit more in some other languages, just the way things are in terms of what is common). Because of this, the constructs it enables aren't as familiar in C# as elsewhere, and your code is more likely to be misread by another dev.
You could use an extension method with a different name:
public static T Put<T, U>(this T collection, U item) where T : ICollection<U> {
collection.Add(item);
return collection;
}
To create code like this:
var list = new List<int>();
list.Put(1).Put(2).Put(3);
To retain the name Add, however, you can have a method like this:
public static T Add<T, U>(this T collection, Func<U> itemProducer)
where T : ICollection<U> {
collection.Add(itemProducer());
return collection;
}
And create code like this:
list.Add(()=>1).Add(()=>2).Add(()=>3);
It doesn't look that good though.
Maybe if we change the type we can have a better syntax.
Given this class:
public class ListBuilder<T> {
IList<T> _list;
public ListBuilder(IList<T> list) {
_list = list;
}
public ListBuilder<T> Add(T item) {
_list.Add(item);
return this;
}
}
You can have this method:
public static ListBuilder<T> Edit<T>(this IList<T> list) {
return new ListBuilder<T>(list);
}
And use code like this:
list.Edit().Add(1).Add(2).Add(3);
I'm sure you won't appreciate this answer but there's a very good reason that List<>.Add() works this way. It is very fast, it needs to be to be competitive with an array and because it is such a low-level method. It is however just a hair too big to get inlined by the JIT optimizer. It cannot optimize the return statement you'd need to return the list reference.
Writing lst.Add(obj) in your code is for free, the lst reference is available in a CPU register.
A version of Add() that returns the reference makes the code almost 5% slower. It's a lot worse for the proposed extension method, there an entire extra stack frame involved.
I like the extension approach that others have mentioned as that seems to answer the question well (although you would have to give it a different method signature than the existing Add()). Also, it does seem like there's some inconsistency about object returns on calls like this (I thought it was a mutability issue, but the stringbuilder is mutable isn't it?), so you raise an interesting question.
I'm curious, though, if the AddRange method would not work as an out-of-the-box solution? Is there a particular reason you want to chain the commands instead of passing everything in as a an array?
Would do something like this not accomplish what you need?
List<string> list = new List<string>();
list.AddRange(new string[]{
"first string",
"second string",
});

Method-Chaining in C#

I have actually no idea of what this is called in C#.
But i want to add the functionallity to my class to add multiple items at the same time.
myObj.AddItem(mItem).AddItem(mItem2).AddItem(mItem3);
The technique you mention is called chainable methods. It is commonly used when creating DSLs or fluent interfaces in C#.
The typical pattern is to have your AddItem() method return an instance of the class (or interface) it is part of. This allows subsequent calls to be chained to it.
public MyCollection AddItem( MyItem item )
{
// internal logic...
return this;
}
Some alternatives to method chaining, for adding items to a collection, include:
Using the params syntax to allow multiple items to be passed to your method as an array. Useful when you want to hide the array creation and provide a variable argument syntax to your methods:
public void AddItems( params MyItem[] items )
{
foreach( var item in items )
m_innerCollection.Add( item );
}
// can be called with any number of arguments...
coll.AddItems( first, second, third );
coll.AddItems( first, second, third, fourth, fifth );
Providing an overload of type IEnumerable or IEnumerable so that multiple items can be passed together to your collection class.
public void AddItems( IEnumerable<MyClass> items )
{
foreach( var item in items )
m_innerCollection.Add( item );
}
Use .NET 3.5 collection initializer syntax. You class must provide a single parameter Add( item ) method, implement IEnumerable, and must have a default constructor (or you must call a specific constructor in the initialization statement). Then you can write:
var myColl = new MyCollection { first, second, third, ... };
Use this trick:
public class MyClass
{
private List<MyItem> _Items = new List<MyItem> ();
public MyClass AddItem (MyItem item)
{
// Add the object
if (item != null)
_Items.Add (item)
return this;
}
}
It returns the current instance which will allow you to chain method calls (thus adding multiple objects "at the same time".
"I have actually no idea of what this is called in c#"
A fluent API; StringBuilder is the most common .NET example:
var sb = new StringBuilder();
string s = sb.Append("this").Append(' ').Append("is a ").Append("silly way to")
.AppendLine("append strings").ToString();
Others have answered in terms of straight method chaining, but if you're using C# 3.0 you might be interested in collection initializers... they're only available when you make a constructor call, and only if your type has appropriate Add methods and implements IEnumerable, but then you can do:
MyClass myClass = new MyClass { item1, item2, item3 };
Why don't you use the params keyword?
public void AddItem (params MyClass[] object)
{
// Add the multiple items
}
You could add an extension method to support this, provided your class inherits from ICollection:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void CanChainStrings()
{
ICollection<string> strings = new List<string>();
strings.AddItem("Another").AddItem("String");
Assert.AreEqual(2, strings.Count);
}
}
public static class ChainAdd
{
public static ICollection<T> AddItem<T>(this ICollection<T> collection, T item)
{
collection.Add(item);
return collection;
}
}
How about
AddItem(ICollection<Item> items);
or
AddItem(params Item[] items);
You can use them like this
myObj.AddItem(new Item[] { item1, item2, item3 });
myObj.AddItem(item1, item2, item3);
This is not method chaining, but it adds multiple items to your object in one call.
If your item is acting as a list, you may want to implement an interface like iList or iEnumerable / iEnumerable.
Regardless, the key to chaining calls like you want to is returning the object you want.
public Class Foo
{
public Foo AddItem(Foo object)
{
//Add object to your collection internally
return this;
}
}
Something like this?
class MyCollection
{
public MyCollection AddItem(Object item)
{
// do stuff
return this;
}
}

Categories

Resources