List<T> and GetRange() issue in derived Class - c#

I have a class that implements a list of MyItems.
I want a method cutting of some elements from that list and it should return the removed items.
This is what I tried:
public class MyItemList : List<MyItem>
{
...
public MyItemList cutOff(int count)
{
MyItemList result = this.GetRange(0, count);
this.RemoveRange(0, count);
return result;
}
Unfortunately the GetRange() returns List but not MyItemList :(
How can I handle this in a better way?
Casting doesn't work.
There must be an elegant way to solve this very simple problem and stay inside the type MyItemList (without dirty hacks).
Thanks in advance!

This should do the trick, but I strongly suggest to redesign towards composition, where you will store List internally
public class MyItemList : List<MyItem>
{
public MyItemList(){}
public MyItemList(IEnumerable<MyItem> sequence): base(sequence) {}
public MyItemList cutOff(int count)
{
MyItemList result = new MyItemList(this.GetRange(0, count));
this.RemoveRange(0, count);
return result;
}
}
Also consider creating open generic type of your list like MyList<T> : List<T> or MyList<T> : List<T> where T : MyItem so that client of that class can take advantage of generics
Edit: ok, I've implemented generic version for List<T> as extension method, this will help you to more logic general to Lists outside your MyItemList class
public static class ListExtensions
{
public static List<T> CutOff<T>(this List<T> list, int count)
{
var result = list.GetRange(0, count);
list.RemoveRange(0, count);
return result;
}
}
now you can
var list = new List<int> {1,2,3,4,5,6};
Console.WriteLine ("cutted items:");
Console.WriteLine (string.Join(Environment.NewLine, list.CutOff(2)));
Console.WriteLine ("items in list:");
Console.WriteLine (string.Join(Environment.NewLine, list));
prints:
cutted items:
1
2
items in list:
3
4
5
6
Another note:
I suggest to do this
public class MyItemList<T> : IList<T> where T : MyItem
{
private List<T> list;
//here will be implementation of all methods required by IList
//that will simply delegate to list field
}
note that if all logic in MyItemList is general-purpose (that can be applied to List<T>, like Cutoff method), you probably don't need separate class. Also where T : MyItem is optional, only need if you access methods defined in MyItem at MyItemList

You could just return a List<MyItem> or MyItem[] with the removed items.
or Use the List<> constructor that takes an ienumerable.
Haven't compiled this - but should be ok
public class MyItemList : List<MyItem>
{
// def ctor
public MyItemList() {}
public MyItemList(IEnumerable<MyItems> items): base(items) {}
public MyItemList cutOff(int count)
{
MyItemList result = new MyItemList(this.GetRange(0, count));
this.RemoveRange(0, count);
return result;
}
}

Don't inherit from List<MyItem> (unless all you're trying to do is avoid typing angle brackets. Rather, encapsulate a List<MyItem> as your class' backing store and expose only the specific/methods and properties required by your problem domain. By inheriting from List<MyObject>, your are leaking implementation details and tying yourself to a particular type of backing store. You want to maintain the minimal public surface area required to get the job done. Doing so facilitates testing, and makes future change much easier.
If you want interoperability with standard SCG collection types, implement only the interfaces you need — preferably explicitly.

Related

What is the "type" of a generic IList<T>?

Imagine an extension like this..
public static Blah<T>(this IList<T> ra)
{
..
}
Imagine you want to make a note of the most recently-called one.
private static IList recent;
public static Blah<T>(this IList<T> ra)
{
recent = ra;
..
}
You actually can not do that:
error CS0266: Cannot implicitly convert type System.Collections.Generic.IList<T> to System.Collections.IList.
1- You can simply make recent an object and that seems to work fine, but it seems like a poor solution.
2- It seems if you do have recent as an IList, you can actually cast the "ra" to that...
recent = (System.Collections.IList)ra;
and it seems to work. Seems strange though?? So,
3- Actually, what type should recent be so that you don't have to cast to it?? How can you make recent the same type as ra? You can't say this ....
private static System.Collections.Generic.IList recent;
it's not meaningful. So what the heck is the type of "ra"? What should recent "be" so that you can simply say recent=ra ?
(I mention this is for Unity, since you constantly use generic extensions in Unity.)
4- Consider a a further difficulty the case if you want to have a Dictionary of them all.
private static Dictionary<object,int> recents = new Dictionary<object,int>();
I can really only see how to do it as an object.
USE CASE EXAMPLE.
Here's an extension you use constantly, everywhere, in game engineering,
public static T AnyOne<T>(this IList<T> ra)
{
int k = ra.Count;
if (k<=0) {Debug.Log("Warn!"+k);}
int r = UnityEngine.Random.Range(0,k);
return ra[r];
}
no problem so far. So,
explosions.AnyOne();
yetAnotherEnemyToDefeat = dinosaurStyles.AnyOne();
and so on. However. Of course, actual random selections feel bad; in practice what you want is a fairly non-repeating order, more like a shuffle. Usually the best thing to do with any list or array is shuffle them, and serve them in that order; perhaps shuffle again each time through. Simple example, you have 20 random sound effects roars , being for when the dino roars. Each time you need one, if you do this
roars.AnyOne();
its OK, but not great. It will sound sort of suck. (Most players will report it as "not being random" or "repeating a lot".) This
roars.NextOne();
is much better. So, NextOne() should, on its own, (a) if we're at the start shuffle the list, (b) serve it in that order, (c) perhaps shuffle it again each time you use up the list. {There are further subtleties, eg, try not to repeat any near the end/start of the reshuffle, but irrelevant here.}
Note that subclassing List (and/or array) would suck for many obvious reasons, it's a job for a simple self-contained extension.
So then, here's a beautiful way to implement NextOne() using a simple stateful extension.
private static Dictionary<object,int> nextOne = new Dictionary<object,int>();
public static T NextOne<T>(this IList<T> ra)
{
if ( ! nextOne.ContainsKey(ra) )
// i.e., we've never heard about this "ra" before
nextOne.Add(ra,0);
int index = nextOne[ra];
// time to shuffle?
if (index==0)
{
Debug.Log("shuffling!"); // be careful to mutate, don't change the ra!
IList<T> temp = ra.OrderBy(r => UnityEngine.Random.value).ToList();
ra.Clear(); foreach(T t in temp) ra.Add(t);
}
T result = ra[index];
++index;
index=index%ra.Count;
nextOne[ra] = index;
return result;
}
This is surely the perfect example of a "stateful extension".
Notice indeed, I just used "object".
I guess in a way, the fundamental question in this QA is, is it best to use the Dictionary of "object" there, or, would something else more typey be better? Really that's the question at hand. Cheers!
If you want a single globally most recent IList<T> where T potentially varies each time, then your only options are to use object or dynamic. Both require casting; the latter just casts automatically.
I think your confusion stems from thinking that IList<T> inherits IList - it doesn't:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
So arguably you could do this, although I don't see any advantage really:
private static IEnumerable recent;
public static void Blah<T>(this IList<T> ra)
{
recent = ra;
...
}
The simplest, and most type-safe, solution is to store a separate value for each T:
private static class RecentHolder<T> {
public static IList<T> Value { get; set; }
}
public static Blah<T>(this IList<T> ra) {
RecentHolder<T>.Value = ra;
}
What is the “type” of a generic IList< T >?
The base type..
Console.WriteLine( new List<int>().GetType().BaseType);
System.Object
The Generic Type definition ...
Console.WriteLine( new List<int>().GetType().GetGenericTypeDefinition());
System.Collections.Generic.List`1[T]
And to expand on SLAKS Answer
Not really. In the absence of a separate common non-generic base class
You can also use interfaces. So you could do...
public interface IName
{
string Name { get; set; }
}
public class Person : IName
{
public string Name { get; set; }
}
public class Dog : IName
{
public string Name { get; set; }
}
Then you could
private static List<IName> recent;
public static Blah<T>(this List<IName> ra)
{
recent = ra;
..
}
and it won't matter if you put Dog or Person in the list.
OR
I can't believe I didn't think about this last night; LINQ to the rescue using object.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
private static class WonkyCache
{
private static List<object> cache = new List<object>();
public static void Add(object myItem)
{
cache.Add(myItem);
}
public static IEnumerable<T> Get<T>()
{
var result = cache.OfType<T>().ToList();
return result;
}
}
public static void Main()
{
WonkyCache.Add(1);
WonkyCache.Add(2);
WonkyCache.Add(3);
WonkyCache.Add(Guid.NewGuid());
WonkyCache.Add("George");
WonkyCache.Add("Abraham");
var numbers = WonkyCache.Get<int>();
Console.WriteLine(numbers.GetType());
foreach(var number in numbers)
{
Console.WriteLine(number);
}
var strings = WonkyCache.Get<string>();
Console.WriteLine(strings.GetType());
foreach(var s in strings)
{
Console.WriteLine(s);
}
}
}
Results:
System.Collections.Generic.List`1[System.Int32]
1
2
3
System.Collections.Generic.List`1[System.String]
George
Abraham
Try:
public static class StatefulRandomizer<T>
// Use IEquatable<T> for Intersect()
where T : IEquatable<T>
{
// this could be enhanced to be a percentage
// of elements instead of hardcoded
private static Stack<T> _memory = new Stack<T>();
private static IEnumerable<T> _cache;
public static void UpdateWith(IEnumerable<T> newCache)
{
_cache = newCache.ToList();
// Setup the stack again, keep only ones that match
var matching = _memory.Intersect(newCache);
_memory = new Stack<T>(matching);
}
public static T GetNextNonRepeatingRandom()
{
var nonrepeaters = _cache
.Except(_memory);
// Not familar with unity.. but this should make
// sense what I am doing
var next = nonrepeaters.ElementAt(UnityEngine.Random(0, nonrepeaters.Count()-1));
// this fast, Stack will know it's count so no GetEnumerator()
// and _cache List is the same (Count() will call List.Count)
if (_memory.Count > _cache.Count() / 2)
{
_memory.Pop();
}
_memory.Push(next);
return next;
}
}

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().

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

Linq with custom base collection

I often find linq being problematic when working with custom collection object.
They are often defened as
The base collection
abstract class BaseCollection<T> : List<T> { ... }
the collections is defined as
class PruductCollection : BaseCollection<Product> { ... }
Is there a better way to add results from a linq expession to this collection than
addrange or concat?
var products = from p in HugeProductCollection
where p.Vendor = currentVendor
select p;
PruductCollection objVendorProducts = new PruductCollection();
objVendorProducts.AddRange(products);
It would be nice if the object returned form the linq query was of my custom collection type. As you seem to need to enumerate the collection two times to do this.
EDIT :
After reading the answers i think the best solution is to implementa a ToProduct() extention.
Wonder if the covariance/contravariance in c#4.0 will help solve these kinds of problems.
The problem is that LINQ, through extension methods on IEnumerable<T>, knows how to build Arrays, Lists, and Dictionaries, it doesn't know how to build your custom collection. You could have your custom collection have a constructor that takes an IEnumerable<T> or you could write you. The former would allow you to use the LINQ result in your constructor directly, the latter would allow you to decorate the LINQ statement with your extension and get back the collection you desire. Either way you'll need to do some sort of conversion from the generic collection to your specialized collection -- either in the constructor or in the extension. Or you could do both...
public static class MyExtensions
{
public static ProductCollection
ToProducts( this IEnumerable<Product> collection )
{
return new ProductCollection( collection );
}
}
public class ProductCollection : BaseCollection<Product>
{
...
public ProductCollection( IEnumerable<Product> collection )
: base( collection )
{
}
...
}
var products = (from p in HugeProductCollection
where p.Vendor = currentVendor
select p).ToProducts();
I can suggest you a way in that you don't have to enumerate the collection 2 times:
abstract class BaseCollection<T> : List<T>
{
public BaseCollection(IEnumerable<T> collection)
: base(collection)
{
}
}
class PruductCollection : BaseCollection<Product>
{
public PruductCollection(IEnumerable<Product> collection)
: base(collection)
{
}
}
var products = from p in HugeProductCollection
where p.Vendor = currentVendor
select p;
PruductCollection objVendorProducts = new PruductCollection(products);
Could this work with a BindingList ? as BindingList does not have a constructor which would take an IEnumerable but does implement it.
BindingList : Collection, IBindingList, IList, ICollection, IEnumerable, ICancelAddNew, IRaiseItemChangedEvents

Categories

Resources