Cast Collection<Derived> to Collection<Base> - c#

Got another simple question here that is eluding me.
I have 2 classes:
namespace Assets
{
public class BaseAsset
{
// Code here
}
}
And
namespace Assets
{
public class Asset : BaseAsset
{
// Code here
}
}
I have a function that returns a collection of Asset from the database and I want another function to execute that function and return a collection of BaseAsset.
I have tried this:
public static Collection<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return (Collection<BaseAsset>)AssetData.getAssets(CategoryId, UserId, CompanyId);
}
but as you can guess, it doesn't work.
If I was working with lists, I could do:
public static List<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return AssetData.getAssets(CategoryId, UserId, CompanyId).Cast<BaseAsset>().ToList();
}
But I would prefer to use a collection, can anyone come up with an elegant solution?
Cheers,
r3plica

This is a very frequently asked question. The name of the feature that you want is generic covariance; that is, the feature that says "if a giraffe is a kind of animal then a list of giraffes is a kind of list of animals."
The problem is that a list of giraffes is not a kind of list of animals. You can put a tiger into a list of animals, but you can't put a tiger into a list of giraffes, and therefore a list of giraffes cannot be used in any context where a list of animals is expected.
The reason you should use IEnumerable<T> instead of Collection<T> is because as of C# 4, IEnumerable<T> is covariant in T, provided that the type arguments provided are both reference types. That is, a sequence of strings can be used as a sequence of objects, because both are reference types. But a sequence of ints cannot be used as a sequence of objects, because one is a value type.
The reason this is safe is because there is no way to insert a tiger into an IEnumerable<Giraffe>.

If you want the ease of .ToList, just write your own .ToCollection extension method. The implementation should be straightforward - take an IEnumerable<T>, loop through it and add everything into a collection with Add.

The problem is that Collection<T> and ICollection<T> are invariant (that is, Collection<BaseAsset> is neither a subtype nor a supertype of Collection<Asset>).
The problem will be very easily solved by returning either IEnumerable<BaseAsset> or IReadOnlyList<BaseAsset> instead of Collection<BaseAsset>.
That is, you can write:
public static IEnumerable<BaseAsset> GetCategoryAssets(int CategoryId, string UserId, string CompanyId)
{
return AssetData.getAssets(CategoryId, UserId, CompanyId);
}
The cast becomes unnecessary.
In general, you should prefer interface types (such as IList<T>, IReadOnlyList<T>, ICollection<T> or IEnumerable<T>) over concrete types (Collection<T> or List<T>) when specifying return values and function parameters.

Instead of trying to cast to the base class, why not just extract an interface and use that.

Since the Collection<T> class has a constructor that takes an IList<T> as an argument, you can always do:
Collection<BaseAsset> = new Collection<BaseAsset>(
assetList.Cast<BaseAsset>().ToList());
Of course, if you need to reuse this behaviour, you could make a CastToCollection extension:
public static Collection<TResult> CastToCollection<TResult>(this IEnumerable source)
{
return new Collection<TResult>(source.Cast<TResult>().ToList());
}

Related

Implement same Generic Interface 2 times with different Generic parameter

I had to implement 2 interface same time with different generic parameter as below. I get confused enough about it. I had no idea which one of them iterate itself in foreach. Now i understand first one is implicitly choosen.
I have tried new BarList().GetEnumerator() but i can not specify type parameter on method level.
Only solution i have found it that casting it to interface like(new BarList() as IEnumerable<string>)
After confusing about it enough. I just wanted to know that this design is not really good idea ? I have to avoid to implement same generic interface one more time ?
class Program
{
static void Main(string[] args)
{
foreach (var item in new BarList())
{
}
}
}
class BarList: IEnumerable<string>, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Edit:
Let me explain why i am going in this way.
I had to Implement IPagedList<T> interface which is inherited from IList<T>. I wanted to write extension method which convert it to My view model. like below
GetAll().ToPagedList(pageindex);//which is returning IPagedList Then i wanted to use it like below;
GetAll().ToPagedList(pageindex).ToViewModel<T,TViewModel>();
For achieve this I tried to return IPagedList<ViewModel> by that extension method.In that case I have to implement IPagedList 2 times with different parameter. But this strategy made confusing things. This is reason of it.
This seems a bit confusing. Why not make it explicit what is happening by adding the enumerators as properties rather than implementing them on the class. For example,
class ProductCollection
{
public IEnumerable<int> EnumerateTheInts { get { //code to produce enumerator }}
public IEnumerable<string> EnumerateTheStringss { get { //code to produce enumerator }}
}
It isn't always bad to implement an open generic interface twice on an object. For example, IHandle could be implemented by a class which can handle two types of T. However, I would find it confusing to implement IEnumerable twice, because you might not enumerate the type you expect in a for-each or in LINQ. Same reasoning for implementing more than one indexer incidentally. The type of your indexer will determine your result, which I can testify to being extremely confusing!
The compiler is picking the IEnumerator<int> GetEnumerator method by following the rules in 8.8.4 of the C# language specification which first looks for an accessible GetEnumerator() method on the BarList type. The only one of those which is available is the one returning IEnumerator<int>.
If you had made that method use explicit interface implementation as well, then it would have gone onto the later stages of section 8.8.4, which states that if there is more than one type T such that there is an implicit conversion from the expression type (BarList here) to IEnumerable<T> then an error is produced.
I would say this is a confusing design - I would probably add properties or methods to retrieve appropriate "views" on the data.
I'd avoid it. However, it depends on your usage.
It will be okay if you just wanted to pass the instance into a function that expects a IEnumerable<string> parameter explicitely:
you won't have to cast
the function won't even 'see' the other interfaces implemented, so there isn't any confusion.
YMMV
Your current design is confusing. While you have not provided any information about the nature of the collection itself, from the name, I can assume you are supposed to iterate over a bunch of products. Perhaps, you should simply have a class of type Product with a string property and an int property and simply return an IEnumerable<Product> instead.
This way, with LINQ extension methods, you can compose the IEnumerable<T> object you actually mean with:
collection.Select(product => product.IntegerProperty)
collection.Select(product => product.StringProperty)
Of course, you can provide helper methods inside the object as well:
class ProductCollection : IEnumerable<Product> {
public IEnumerable<Product> GetEnumerator() {
// ... return Product objects here.
}
public IEnumerable<int> AsIntegerCollection() {
// yield the integer collection here
}
public IEnumerable<string> AsStringCollection() {
// yield the string collection here
}
}
What are these collections of string and ints? I suppose they mean something in relation with the Product (for example Name, Id, etc...) so I would rather do something like this:
class ProductCollection : IEnumerable<Product>
{
public IEnumerator<Product> GetEnumerator()
{
...
}
public IEnumerator<string> ProductNames // a helper to enumerate product names
{
...
}
public IEnumerator<int> ProductIds // a helper to enumerate product ids
{
...
}
}

How do I get Distinct() to work with a collection of custom objects

I have followed the suggestions from this post to try and get Distinct() working in my code but I am still having issues. Here are the two objects I am working with:
public class InvoiceItem : IEqualityComparer<InvoiceItem>
{
public InvoiceItem(string userName, string invoiceNumber, string invoiceAmount)
{
this.UserName = userName;
this.InvoiceNumber= invoiceNumber;
this.InvoiceAmount= invoiceAmount;
}
public string UserName { get; set; }
public string InvoiceNumber { get; set; }
public double InvoiceAmount { get; set; }
public bool Equals(InvoiceItem left, InvoiceItem right)
{
if ((object)left.InvoiceNumber == null && (object)right.InvoiceNumber == null) { return true; }
if ((object)left.InvoiceNumber == null || (object)right.InvoiceNumber == null) { return false; }
return left.InvoiceNumber == right.InvoiceNumber;
}
public int GetHashCode(InvoiceItem item)
{
return item.InvoiceNumber == null ? 0 : item.InvoiceNumber.GetHashCode();
}
}
public class InvoiceItems : List<InvoiceItem>{ }
My goal is to populate an InvoiceItems object (we will call it aBunchOfInvoiceItems) with a couple thousand InvoiceItem objects and then do:
InvoiceItems distinctItems = aBunchOfInvoiceItems.Distinct();
When I set this code up and run it, I get an error that says
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'InvoiceReader.Form1.InvoiceItems'. An explicit conversion exists (are you missing a cast?)
I don't understand how to fix this. Should I be taking a different approach? Any suggestions are greatly appreciated.
Distinct returns a generic IEnumerable<T>. It does not return an InvoiceItems instance. In fact, behind the curtains it returns a proxy object that implements an iterator that is only accessed on demand (i.e. as you iterate over it).
You can explicitly coerce it into a List<> by calling .ToList(). You still need to convert it to your custom list type, though. The easiest way is probably to have an appropriate constructor, and calling that:
public class InvoiceItems : List<InvoiceItem> {
public InvoiceItems() { }
// Copy constructor
public InvoiceItems(IEnumerable<InvoiceItems> other) : base(other) { }
}
// …
InvoiceItems distinctItems = new InvoiceItems(aBunchOfInvoiceItems.Distinct());
Konrad Rudolph's answer should tackle your compilation problems. There is one another important semantic correctness issue here that has been missed: none of your equality-logic is actually going to be used.
When a comparer is not provided to Distinct, it uses EqualityComparer<T>.Default. This is going to try to use the IEquatable<T> interface, and if this is missing, falls back on the plain old Equals(object other) method declared on object. For hashing, it will use the GetHashCode() method, also declared on object. Since the interface hasn't been implemented by your type, and none of the aforementioned methods have been overriden, there's a big problem: Distinct will just fall back on reference-equality, which is not what you want.
Tthe IEqualityComparer<T> interface is typically used when one wants to write an equality-comparer that is decoupled from the type itself. On the other hand, when a type wants to be able to compare an instance of itself with another; it typically implements IEquatable<T>. I suggest one of:
Get InvoiceItem to implement IEquatable<InvoiceItem> instead.
Move the comparison logic to a separate InvoiceItemComparer : IEqualityComparer<InvoiceItem> type, and then call invoiceItems.Distinct(new InvoiceItemComparer());
If you want a quick hack with your existing code, you can do invoiceItems.Distinct(new InvoiceItem());
Quite simply, aBunchOfInvoiceItems.Distinct() returns an IEnumerable<InvoiceItem> and you are trying to assign that to something that is not an IEnumerable<InvoiceItem>.
However, the base class of InvoiceItems has a constructor that takes such an object, so you can use this:
public class InvoiceItems : List<InvoiceItem>
{
public InvoiceItems(IEnumerable<InvoiceItem> items)
base(items){}
}
Then you can use:
InvoiceItems distinctItems = new InvoiceItems(aBunchOfInvoiceItems.Distinct());
As is though, I don't see much benefit in deriving from List<InvoiceItem> so I would probably lean more toward:
List<InvoiceItem> distinctItems = aBunchOfInvoiceItems.Distinct().ToList();
The error has everything to do with your class InvoiceItems, which inherits from List<InvoiceItem>.
Distinct returns an IEnumerable<InvoiceItem>: InvoiceItems is a very specific type of IEnumerable<InvoiceItem>, but any IEnumerable<InvoiceItem> is not necessarily an InvoiceItems.
One solution could be to use an implicit conversion operator, if that's what you wanted to do: Doh, totally forgot you can't convert to/from interfaces (thanks Saed)
public class InvoiceItems : List<InvoiceItem>
{
public InvoiceItems(IEnumerable<InvoiceItem> items) : base(items) { }
}
Other things to note:
Inheriting from List<T> is usually bad. Implement IList<T> instead.
Using a list throws away one of the big benefits of LINQ, which is lazy evaluation. Be sure that prefetching the results is actually what you want to do.
Aside from the custom class vs IEnumerable issue that the other answers deal with, there is one major problem with your code. Your class implements IEqualityComparer instead of IEquatable. When you use Distinct, the items being filtered must either implement IEquatable themselves, or you must use the overload that takes an IEqualityComparer parameter. As it stands now, your call to Distinct will not filter the items according to the IEqualityComparer Equals and GetHashCode methods you provided.
IEqualityComparer should be implemented by another class than the one being compared. If a class knows how to compare itself, like your InvoiceItem class, it should implement IEquatable.

Adding a collection of a subclass with AddRange

If I have these two classes:
class A {}
class B : A {}
and I make a List<A> but I want to add a List<B> to it by calling List<A>.AddRange(List<B>) but the compiler refuses:
Argument '1': cannot convert from 'System.Collections.Generic.List<A>'
to 'System.Collections.Generic.IEnumerable<B>
which I completely understand because IEnumerable<B> does not inherit from IEnumerable<A>, its generic type has the inheritance.
My solution is to enumerate through List<B> and individually add items because List<A>.Add(A item) will work with B items:
foreach(B item in listOfBItems)
{
listOfAItems.Add(item);
}
However, that's rather non-expressive because what I want is just AddRange.
I could use
List<B>.ConvertAll<A>(delegate(B item) {return (A)item;});
but that's unnecessarily convoluted and a misnomer because I'm not converting, I'm casting .
Question: If I were to write my own List-like collection what method would I add to it that would allow me to copy a collection of B's into a collection of A's as a one-liner akin to List<A>.AddRange(List<B>) and retain maximum type-safety. (And by maximum I mean that the argument is both a collection and type inhertance checking.)
Indeed, generic types are not variant right now. In C# 4.0, IEnumerable<B> will be convertible to IEnumerable<A> if B is convertible to A via a reference conversion. For some details on the design of this feature, see:
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
This does unfortnuately not work because generics in .net do not (yet) support covariance.
You can make a small helper method or class to overcome this issue however.
If you implement your own list class, you can add covariance using an additional generic parameter:
class MyList<T> {
void AddRange<U>(IEnumerable<U> items) where U: T {
foreach (U item in items) {
Add(item);
}
}
}
Can't you just do:
listOfAItems.AddRange(listOfBItems.Cast<A>());
I was able to achieve this using LINQ...
listOfAItems.AddRange(listOfBItems.Cast<A>());
In case you find yourself in a situation where generic types are not variant, the following extension method can make your life easier:
public static void AddRange<TList,TOther>(this List<TList> list, IEnumerable<TOther> collection) where TOther: TList {
foreach(TOther e in collection) {
list.Add(e);
}
}
Instead of having to derive from List<T> or having this method in some utility class, using it as an extension method simplifies usage. You can also profit from inference, so this formerly invalid call will become valid without any modification:
List<Animal> animals;
List<Dog> dogs;
animals.AddRange(dogs);
The only thing I can come up with is this
public class MyList<T> : List<T>
{
public void AddRange<Tother>(IEnumerable<Tother> col)
where Tother: T
{
foreach (Tother item in col)
{
this.Add(item);
}
}
}
Calling it means doing MyList<A>.AddRange<B>(MyList<B>). This fails if the argument is not enumerable or if the type inheritance doesn't work out so it satisfies my question's maximum type safety requirement.

Generics or not Generics

Basically I have a custom List class that contains different fruits. Assume that each fruit has an ID number that is stored in the list.
Is it better to have:
new AppleList();
new OrangeList();
new LemonList();
or
new FruitList<Fruit.Apple>();
new FruitList<Fruit.Orange>();
new FruitList<Fruit.Lemon>();
Things to consider:
All IDs are of type int.
The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.
I would like to use the one that is clearer, better in design, faster, more efficient, etc. Additionally if these above 2 techniques are not the best, please suggest your ideas.
EDIT: Btw Fruit is an enum if that wasn't clear.
Use a combo:
public class AppleList : FruitList<Apple> { ... }
public class OrangeList : FruitList<Orange> { ... }
public class LemonList : FruitList<Lemon> { ... }
Put the common logic in the base list class:
public class FruitList<T> : List<T>
where T : IFruit
{ ... }
If you use generics, is there a purpose to create the FruitList type? Could you just use List?
There won't be much difference in performance, so I say why create three different classes when one would do the same exactly thing? Use the generic solution.
It's much easier to maintain 1 generic list than 3 non-generic versions. If you really like the AppleList name you can always use the using trick to name a generic list
using AppleList=Fruit.FruitList<Fruit.Apple>
•All IDs are of type int.
•The type of the fruit will not affect the implementation of the List itself. It will only be used by the client of the list, like an external method, etc.
Given these two facts, I wouldn't bother with generics. I would put a normal property on FruitList to indicate which type of fruit it is.
Reuse the generic collection classes and subclass them only if you're adding additional functionality. Keep your subclass implementation generic if you can. This is the least complex implementation.
Use the Generic list, no point in crating 3 lists and it's always good to keep a level of abstraction. (IFruit would be a good interface).
I would not recommend the accepted answer and I think you meant something like this instead:
public enum Fruit
{
Apple,
Orange,
Lemon
}
public interface IFruitList : IList<int>
{
Fruit Type { get; }
};
public class FruitList : List<int>, IFruitList
{
private readonly type;
FruitList(Fruit type)
: base()
{
this.type = type;
}
FruitList(Fruit type, IEnumerable<int> collection)
: base(collection)
{
this.type = type;
}
Fruit Type { return type; }
}
You should assume YAGNI unless you need it. Therefore, if you don't need antyhing more than you get in List, then just List<T>. If for some reason you have to override List, then create
FruitList<T> : List<T> where T : Fruit
If your lists diverge and are no longer polymorphic, then consider implementing your custom lists:
AppleList
OrangeList
LemonList
Try as best you can, however, to keep your inheritance hierarchy as flat as possible to avoid overcomplicating your solution.

.NET: How to check the type within a generic typed class?

How do I get the type of a generic typed class within the class?
An example:
I build a generic typed collection implementing ICollection< T>. Within I have methods like
public void Add(T item){
...
}
public void Add(IEnumerable<T> enumItems){
...
}
How can I ask within the method for the given type T?
The reason for my question is: If object is used as T the collection uses Add(object item) instead of Add(IEnumerable<object> enumItems) even if the parameter is IEnumerable. So in the first case it would add the whole enumerable collection as one object instead of multiple objects of the enumerable collection.
So i need something like
if (T is object) {
// Check for IEnumerable
}
but of course that cannot work in C#. Suggestions?
Thank you very much!
Michael
You can use: typeof(T)
if (typeof(T) == typeof(object) ) {
// Check for IEnumerable
}
Personally, I would side step the issue by renaming the IEnumerable<T> method to AddRange. This avoids such issues, and is consistent with existing APIs such as List<T>.AddRange.
It also keeps things clean when the T you want to add implements IEnumerable<T> (rare, I'll admit).
If you want to use the is operator in a generic class/method you have to limit T to a reference type:
public void MyMethod<T>(T theItem) where T : class
{
if (theItem is IEnumerable) { DoStuff(); }
}

Categories

Resources