|
Smithers-Jones wrote: He definitely astonished me with his exceptional first impression of an angry elephant with constipation
5
|
|
|
|
|
Smithers-Jones wrote: an angry elephant with constipation
Smithers-Jones wrote: a monkey with rabies
Is this you subtly suggesting the development of a zoo management system? some merger of a hotel management system and a patient tracking system?
|
|
|
|
|
This has got to be one of the best, most constructive forum replies ever. It's just a shame it's too long for a quote in a signature!
5 from me
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
DaveyM69 wrote: It's just a shame it's too long for a quote in a signature!
You could try to cut down its length by using textspeak
"I love deadlines. I like the whooshing sound they make as they fly by." (DNA)
|
|
|
|
|
Thanks Dave. You could always use the "Astonish Us. Be Exceptional" bit if you like.
|
|
|
|
|
Done
|
|
|
|
|
Wow. Is that 3 sig lines I've got going on in there? Thanks very much Dave - that's pretty humbling.
|
|
|
|
|
You keep coming up with these gems - I just steal quote them!
|
|
|
|
|
Oooh look a troll. All wet and slimy under the bridge is it?
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Hello All ,
I have used a CalendarExtender in my page with textboxes. When I press enter key in another textbox, calendar's popup is appearing.
I have used defaultbutton attribute in form tag and tried keeping my button id as defalut button but this is also not working.
Please help me out in same..
Thanks In Advance
|
|
|
|
|
Smells like ASP.Net to me. You will get better responses in that forum.
|
|
|
|
|
Hi guys,
I need to find a way around a problem so that I can have an array containing lists of different types, where those types are all derived from the same class. Unfortunately I'm at the end of my knowledge of covariance etc so any help would be greatly appreciated.
To explain better:
I have a class ('class X') which has several lists in it. The lists contain different types, but these types all derive from the same abstract class. I need to be able to iterate through all items (i.e. across and within the lists) as though all the lists were one. For various reasons, the lists must remain as separate objects. Furthermore, 'Class X' is inherited, and derived classes have additional lists...
My solution was to create an array containing these lists (which makes iterating with an unknown number of lists very easy), but I hit problems very quickly (e.g. see code below). Can anyone show me how to do something like this, or find a more elegant way to do it?
Here's a much smaller, simple example of the kind of thing I'm trying to do:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
abstract class A
{ }
class B : A
{ }
class C : A
{ }
class ClassX
{
static void DoStuff()
{
List<B> listB = new List<B>();
List<C> listC = new List<C>();
List<A>[] arrayOfLists = new List<A>[2];
arrayOfLists[0] = listB;
arrayOfLists[1] = listC;
arrayOfLists[0] = listB.Cast<A>().ToList();
List<List<A>> listOfLists = new List<List<A>>();
listOfLists.Add(listB);
}
}
}
Thanks!
Lee
|
|
|
|
|
The List(T) class is neither covariant nor contravariant.
Here is why:
If you have a list of class A, you can't cast it to a list of class B (derived from A), because not all instances of class A are also instances of class B. This is obvious.
Now the other way: why is it impossible to cast a list of clas B (derived from A) to a list of class A? Because then you could add an item of class C (derived from A) to the list, although it is actually a list of B.
If you only need to iterate throught all the items (thus the full list can be read-only), then you can create a custom iteration logic by implementing the IEnumerable(T) and IEnumerator(T) interfaces, that's probably what I would do... Instead of adding a new List(A) to the class, create a method that returns IEnumerable(A) and implement the iteration logic.
|
|
|
|
|
Hey Kubajzz, thanks for your reply.
I understand what you've said. Problem is that kind of jump-to-the-next-list iteration logic makes the whole thing very messy when the List<B>, List<C>, etc lists are not in some sort of collection (i.e. where it is obvious as to which list to jump to without needing special programming).
It also raises the problem that every class that subsequently derives from 'ClassX' requires a decent amount of overriding/patching if they add new lists (e.g. List<D>, List<E>). My project has several deriving classes, and values being entirely 'readonly' defeats the purpose of the whole class
Is there not an easy way to collect these lists together in some sort of collection?
Thanks heaps for your time
<div class="modified">modified on Monday, September 6, 2010 6:52 AM</div>
|
|
|
|
|
Lee Reid wrote: My project has several deriving classes, and values being entirely 'readonly' defeats the purpose of the whole class
I thought you only needed the complete list for iterating through all lists, thus a read-only iterator (such as IEnumerator) could be enough.
IEnumerable(T) can be implemented in a very clean way without the need of any "special programming".
See the following example:
class A {}
class B : A {}
class C : A {}
class MyClass {
private List<B> listB;
private List<C> listC;
public MyClass() {
}
public IEnumerable<A> GetAllItems() {
IEnumerable<A> b = listB;
IEnumerable<A> c = listC;
return b.Concat(c);
}
}
Yes, it is this simple. Note that the GetAllItems method could easily be 1-line long. You can implement some logic to get all the lists in the current class as an array of IEnumerable<A> for easy overriding, it's not more than 1 or 2 very short methods... I don't think this is messy, nor does it require any "special programming" and I highly doubt there is easier and simpler solution.
The one and only question is: does IEnumerable provide enough functionality for your application?
|
|
|
|
|
Absolutely perfect!
Thank you so much; I've not used ienumerable and related interfaces before, and didn't realise quite how elegant/easy/functional they could be. You've relieved quite a headache of mine!
Thanks again
|
|
|
|
|
I'm glad it helped...
Here are 2 more notes to make my answer a bit more complete. I assume you aready know all this, but it coud be useful to someone:
- The System.Linq namespace is your best friend when working with IEnumerable(T).
- The yield return statement is an awesome language feature... http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
|
|
|
|
|
As has been explained, it can't be done with an implicit or explicit cast.
Here is a little method to do it for you.
public static List<TBase> DerivedConverter<TBase, TDerived>(List<TDerived> derivedList)
where TDerived : TBase
{
return derivedList.ConvertAll<TBase>(
new Converter<TDerived, TBase>(delegate(TDerived derived)
{
return derived;
}));
}
To use:
List<Base> listBase = DerivedConverter<Base, Derived>(listDerived);
where Base is the base class and Derived is a class derived from Base .
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
|
Sort of. The item references are copied so any changes to an element in listB will be reflected in listA .
Test Code:
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Derived derived1 = new Derived(1);
Derived derived2 = new Derived(2);
List<Derived> listDerived = new List<Derived>(new Derived[] { derived1, derived2 });
List<Base> listBase = DerivedConverter<Base, Derived>(listDerived);
listDerived[0].ID = 0;
for (int i = 0; i < listBase.Count; i++)
{
Console.WriteLine("{0} {1}",
object.ReferenceEquals(listBase[i], listDerived[i]),
listBase[i].ID);
}
Console.ReadKey();
}
public static List<TBase> DerivedConverter<TBase, TDerived>(List<TDerived> derivedList)
where TDerived : TBase
{
return derivedList.ConvertAll<TBase>(
new Converter<TDerived, TBase>(delegate(TDerived derived)
{
return derived;
}));
}
}
public class Base
{
public Base(int id)
{
ID = id;
}
public int ID { get; set; }
}
public class Derived : Base
{
public Derived(int id)
: base(id)
{ }
}
If you add or remove items to listB then that won't be reflected in listA unless you rebuild it dynamically.
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Perhaps something like this will help. This implementation doesn't allow you to add items to the base list, I don't know if that is a requirement or not. This won't be particularly efficient but should work (untested!). You would need to add checks to make sure the lists aren't null too.
public class BaseList<TBase, TDerived1, TDerived2>
where TDerived1 : TBase
where TDerived2 : TBase
{
private List<TDerived1> derived1List;
private List<TDerived2> derived2List;
public List<TDerived1> Derived1List
{
get { return derived1List; }
set { derived1List = value; }
}
public List<TDerived2> Derived2List
{
get { return derived2List; }
set { derived2List = value; }
}
public ReadOnlyCollection<TBase> BaseCollection
{
get
{
List<TBase> baseList = DerivedConverter<TBase, TDerived1>(derived1List);
baseList.AddRange(DerivedConverter<TBase, TDerived2>(derived2List));
return baseList.AsReadOnly();
}
}
private static List<TBase> DerivedConverter<TBase, TDerived>(List<TDerived> derivedList)
where TDerived : TBase
{
return derivedList.ConvertAll<TBase>(
new Converter<TDerived, TBase>(delegate(TDerived derived)
{
return derived;
}));
}
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Thanks Dave!
while not being the 'perfect' solution, you seem to have inadvertently solved another problem of mine, which I hadn't put to the forums yet!
I appreciate the help
|
|
|
|
|
You're welcome
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.(Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
|
Would this help?
public static System.Collections.Generic.IEnumerable<T>
Enumerate<T>
(
params System.Collections.Generic.IEnumerable<T>[] Lists
)
{
foreach
(
System.Collections.Generic.IEnumerable<T> list
in
Lists
)
{
foreach
(
T t
in
list
)
{
yield return ( t ) ;
}
}
yield break ;
}
|
|
|
|