Casting an object to a base collection - c#

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.

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.

Inheritance and return types [duplicate]

public interface IDic
{
int Id { get; set; }
string Name { get; set; }
}
public class Client : IDic
{
}
How can I cast List<Client> to List<IDic>?
You can't cast it (preserving reference identity) - that would be unsafe. For example:
public interface IFruit {}
public class Apple : IFruit {}
public class Banana : IFruit {}
...
List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());
// Eek - it's a banana!
Apple apple = apples[0];
Now you can convert a List<Apple> to an IEnumerable<IFruit> in .NET 4 / C# 4 due to covariance, but if you want a List<IFruit> you'd have to create a new list. For example:
// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();
// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();
But this is not the same as casting the original list - because now there are two separate lists. This is safe, but you need to understand that changes made to one list won't be seen in the other list. (Modifications to the objects that the lists refer to will be seen, of course.)
A Cast iterator and .ToList():
List<IDic> casted = input.Cast<IDic>().ToList() will do the trick.
Originally I said covariance would work - but as Jon has rightly pointed out; no it won't!
And originally I also stupidly left off the ToList() call
I too had this problem and after reading Jon Skeet's answer I modified my code from using List<T> to use IEnumerable<T>. Although this does not answer the OP's original question of How can I cast List<Client> to List<IDic>, it does avoid the need to do so and thus may be helpful to others who encounter this issue. This of course assumes that the code that requires the use of List<IDic> is under your control.
E.g.:
public void ProcessIDic(IEnumerable<IDic> sequence)
{
// Implementation
}
Instead of:
public void ProcessIDic(List<IDic> list)
{
// Implementation
}
If you can use LINQ then you can do this...
List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();
List<Client> listOfA = new List<Client>();
List<IDic> list = listOfA.Cast<IDic>().ToList();
Its only possible by creating new List<IDic> and transfering all elements.
In .Net 3.5, you can do the following:
List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());
The constructor for List in this case takes an IEnumerable.
list though is only convertible to IEnumerable. Even though myObj may be convertible to ISomeInterface the type IEnumerable is not convertible to IEnumerable.
OfType
You can try something like:
using (var dbContext = YourDatabaseContext())
{
var list = dbContext.Clients.Where(x => x.Happy)
.OfType<IDic>()
.ToList();
}
See https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype
If you want to process the original list without creating a separated reference, you could define the generic method like this:
public void DoIterate<T>(List<T> myCollection) where T : IDic
{
foreach (T item in myCollection)
{
//update a property of interface
item.Name = "new Name";
}
}
Calling this method above to process the list without having to cast specific object to interface:
List<Client> clients = new List<Client>();
DoIterate(clients);
If you don't need to modify the contents of the original list, you can implicitly convert a List into a IReadOnlyList which will let you iterate over it's contents as IDics without creating a new list.
List<Client> myClients = new List<Client>();
myClients.Add(new Client());
IReadOnlyList<IDic> castedClients = myClients;
foreach(IDic val in castedClients)
{
//do something;
}
The conversion can also occur while simply returning the list like so :
public IReadOnlyList<IDic> getClientsAsIDic()
{
return myClients;
}

Is there a good way to clear an ICollection<T> without knowing T?

I have a list of collections of various item types.
The list is typed as List<IEnumerable>; because IEnumerable is the only non-generic interface from ICollection<T>, and I need to add e.g. ICollection<Contact> and ICollection<Partnership> collections in this list.
Later, in entity utility code, I need to clear the collections. The only solution I've found so far is:
collection.GetType().GetInterface("ICollection`1").InvokeMember("Clear",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
null,
collection,
new object[0]);
Is there anything more elegant I can use?
There aren't many options if you're constrained by ICollection<T> as your lowest type. A less-wordy implementation that involves the DLR is to use dynamic and duck-type it:
static void Main(string[] args)
{
var listOfLists = new List<IEnumerable>();
var names = new List<string>();
var ages = new List<int>();
listOfLists.Add(names);
listOfLists.Add(ages);
foreach (dynamic list in listOfLists)
{
list.Clear();
}
}
Or you can make assumptions about possibly implemented interfaces and test for one with Clear defined:
foreach (var list in listOfLists)
{
if (list is IList)
{
(list as IList).Clear();
}
}
If you can get into the type hierachy, create your own interface that your collections use and define your own Clear.
This is mainly a problem because the pre-.NET 2.0 collections and interfaces do not mesh well with the .NET 2.0 collections and interfaces.
You might use a common interface for your business classes, like IObject (or maybe even the object class). Try this:
class Program
{
static void Main(string[] args)
{
var list = new MyList();
var contacts = new ContactCollection();
var partnerships = new PartnershipCollection();
contacts.Add(new Contact());
partnerships.Add(new Partnership());
list.Add(contacts);
list.Add(partnerships);
list.ClearCollections();
}
class MyList : List<ICollection<IObject>>
{
public void ClearCollections()
{
this.ForEach((a) => a.Clear());
}
}
interface IObject { }
class Contact : IObject { }
class Partnership : IObject { }
class ContactCollection : ICollection<IObject> { }
class PartnershipCollection : ICollection<IObject> { }
}
Why do you need to use Reflection? as the ICollection interface includes the Clear method then whatever concrete type that implements this will have it covered.
So simply
ICollection collection = new List<Something>();
collection.Clear();
will do

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",
});

Generic method to create deep copy of all elements in a collection

I have various ObservableCollections of different object types. I'd like to write a single method that will take a collection of any of these object types and return a new collection where each element is a deep copy of elements in the given collection. Here is an example for a specifc class
private static ObservableCollection<PropertyValueRow> DeepCopy(ObservableCollection<PropertyValueRow> list)
{
ObservableCollection<PropertyValueRow> newList = new ObservableCollection<PropertyValueRow>();
foreach (PropertyValueRow rec in list)
{
newList.Add((PropertyValueRow)rec.Clone());
}
return newList;
}
How can I make this method generic for any class which implements ICloneable?
You could do something like this:
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
Note that you could make this more general by taking IEnumerable<T>, and LINQ makes it even easier:
private static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
where T : ICloneable
{
return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());
}
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
I use a very similar function which works with all ICollections which can be constructed (e.g. many standard collections):
public static TContainer CloneDeep<TContainer, T>( TContainer r )
where T : ICloneable
where TContainer: ICollection<T>, new()
{
// could use linq here, but this is my original pedestrian code ;-)
TContainer l = new TContainer();
foreach(var t in r)
{
l.Add( (T)t.Clone() );
}
return l;
}
Unfortunately the compiler isn't able to deduce the types so that one must pass them explicitly. For more than a handful calls I write a specialization. Here is an example for Lists (which itself can be called with implicitly deduced T).
public static List<T> CloneListDeep<T>( List<T> r ) where T : ICloneable
{
return CloneDeep<List<T>, T>( r );
}
I use this function extensively in order to create copies of lists serving as datasources for datagridviews on dialogs which can be canceled. The modified list is simply discarded when the dialog is cancelled; when the dialog is OKed the edited list simply replaces the original. Prerequisite for this pattern is, of course, to have a semantically correct and well maintained T.clone().

Categories

Resources