.NET Forum / Languages / C# / February 2008
Generics and Findall
|
|
Thread rating:  |
tshad - 19 Feb 2008 20:49 GMT I am confused as to why you need to use Predicate<t> in a findall method of Generics.
I have the following which works fine.
********************************************************* using System; using System.Collections.Generic; using System.Text;
namespace Generics { public class Racer { private string name; public string Name { get{return name;}} private string car; public string Car {get {return car;}} public Racer(string name, string car) { this.name = name; this.car = car; } public override string ToString() { return name + ", " + car; }
public bool GetCar(string theCar) { return this.car == theCar; }
public bool GetName(string theName) { return this.name == theName; } }
public class FindRacer { private string car; public FindRacer(string car) { this.car = car; } public bool DrivingCarPredicate(Racer racer) { return racer.Car == car; } } class Program { public static void GetDino() { List<string> dinosaurs = new List<string>();
dinosaurs.Add("Compsognathus"); dinosaurs.Add("Amargasaurus"); dinosaurs.Add("Oviraptor"); dinosaurs.Add("Velociraptor"); dinosaurs.Add("Deinonychus"); dinosaurs.Add("Dilophosaurus"); dinosaurs.Add("Gallimimus"); dinosaurs.Add("Triceratops");
Console.WriteLine(); foreach (string dinosaur in dinosaurs) { Console.WriteLine(dinosaur); }
Console.WriteLine("\nTrueForAll(EndsWithSaurus): {0}", dinosaurs.TrueForAll(EndsWithSaurus));
Console.WriteLine("\nFind(EndsWithSaurus): {0}", dinosaurs.Find(EndsWithSaurus));
Console.WriteLine("\nFindLast(EndsWithSaurus): {0}", dinosaurs.FindLast(EndsWithSaurus));
Console.WriteLine("\nFindAll(EndsWithSaurus):"); List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);
foreach (string dinosaur in sublist) { Console.WriteLine(dinosaur); }
Console.WriteLine( "\n{0} elements removed by RemoveAll(EndsWithSaurus).", dinosaurs.RemoveAll(EndsWithSaurus));
Console.WriteLine("\nList now contains:"); foreach (string dinosaur in dinosaurs) { Console.WriteLine(dinosaur); }
Console.WriteLine("\nExists(EndsWithSaurus): {0}", dinosaurs.Exists(EndsWithSaurus)); }
// Search predicate returns true if a string ends in "saurus". private static bool EndsWithSaurus(String s) { if ((s.Length > 5) && (s.Substring(s.Length - 6).ToLower() == "saurus")) { return true; } else { return false; } }
static void Main(string[] args) {
GetDino();
List<Racer> racers = new List<Racer>(); racers.Add(new Racer("Michael Schumacher", "Ferrari")); racers.Add(new Racer("Juan Pablo Montoya", "McLaren-Mercedes")); racers.Add(new Racer("Kimi Raikkonen", "McLaren-Mercedes")); racers.Add(new Racer("Mark Webber", "Williams-BMW")); racers.Add(new Racer("Rubens Barichello", "Ferrari"));
foreach (Racer r in racers) { Console.WriteLine(r); }
FindRacer finder = new FindRacer("Ferrari"); foreach (Racer racer in racers.FindAll(new Predicate<Racer>(finder.DrivingCarPredicate))) { Console.WriteLine(racer); }
List<Racer> theList = racers.FindAll(new Predicate<Racer>(finder.DrivingCarPredicate));
Console.Read(); } } } *********************************************************
All this code works perfectly.
But for Racers, I do the FindAll method with:
List<Racer> theList = racers.FindAll(new Predicate<Racer>(finder.DrivingCarPredicate));
In the GetDino method I use the following with no "Predicate<t>":
List<string> sublist = dinosaurs.FindAll(EndsWithSaurus);
Why is that?
Also, I tried set up 2 predicates similar to the GetDino method and put the methods in the Racers Class (GetCar and GetName) but I can't get it to work:
List<Racer> theList = racers.FindAll(theList.GetCar("Ferrari"));
This will give me the error:
'System.Collections.Generic.List<Generics.Racer>' does not contain a definition for 'GetCar'
but the class Racer does contain it.
Do you have to create a whole new class (as I do with FindRacer) to get this to work?
Thanks,
Tom
Peter Duniho - 19 Feb 2008 21:18 GMT > I am confused as to why you need to use Predicate<t> in a findall method > of > Generics. I suppose that depends on your definition of "use". The parameter for the FindAll() method is a Predicate<T>, so you must use some instance of an appropriate Predicate<T>.
But type inference can take a method name and convert it to the necessary instance without explicitly writing "Predicate<T>", so in that sense you don't need to use Predicate<T> in a call to the FindAll() method.
> [...] > But for Racers, I do the FindAll method with: [quoted text clipped - 7 lines] > > Why is that? Because the second example takes advantage of type inference. You should be able to get the first example to work fine in a similar way:
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);
> Also, I tried set up 2 predicates similar to the GetDino method and put > the [quoted text clipped - 8 lines] > 'System.Collections.Generic.List<Generics.Racer>' does not contain a > definition for 'GetCar' Well, it doesn't. "theList" is an instance of List<Racer>, and it only contains the methods declared in the generic List<T> class. Where would it get the GetCar() method from?
If you want to use the GetCar() method as the predicate, you need to a) have a list that contains strings rather than Racers (since the method's argument is a string not a Racer), and b) reference the method from an instance of Racer, not from an instance of List<T>.
> but the class Racer does contain it. Yes, which is why you need an instance of Racer, not an instance of List<Racer>.
> Do you have to create a whole new class (as I do with FindRacer) to get > this > to work? No. You didn't really even need the FindRacer class. Anonymous methods are really useful when dealing with predicates. For example, instead of:
FindRacer finder = new FindRacer("Ferrari"); List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);
with all of the overhead of declaring that FindRacer class, you could have just used:
List<Racer> theList = racers.FindAll(delegate(Racer racer) { return racer.Car == "Ferrari"; });
without having to declare any new class at all.
Pete
Tom Shelton - 19 Feb 2008 21:30 GMT <snip>
>> [...] >> But for Racers, I do the FindAll method with: [quoted text clipped - 19 lines] > List<Racer> theList = racers.FindAll(delegate(Racer racer) { return > racer.Car == "Ferrari"; }); And in C# 3.0:
List<Racer> theList = racers.FindAll (racer => racer.Car == "Farrari");
 Signature Tom Shelton
tshad - 20 Feb 2008 17:44 GMT >> I am confused as to why you need to use Predicate<t> in a findall method >> of [quoted text clipped - 7 lines] >instance without explicitly writing "Predicate<T>", so in that sense you >don't need to use Predicate<T> in a call to the FindAll() method. That would make more sense,
Why use it if you don't need it?
>> [...] >>But for Racers, I do the FindAll method with: [quoted text clipped - 29 lines] >contains the methods declared in the generic List<T> class. Where would it >get the GetCar() method from? I just assumed that since List is a List/Collection of Racer classes that each class would have the method and be able to call it.
Obviously, this is not the case.
>If you want to use the GetCar() method as the predicate, you need to a) >have a list that contains strings rather than Racers (since the method's >argument is a string not a Racer), and b) reference the method from an >instance of Racer, not from an instance of List<T>. But I need the Racers class as that is what I am using for my data collection. If I was only going to use strings, why not use an Array class.
>> but the class Racer does contain it. > [quoted text clipped - 18 lines] > >without having to declare any new class at all. That worked really well.
I have been trying to see why to use delegates at all and this seems to be a really good place.
Thanks,
Tom
>Pete tshad - 20 Feb 2008 17:59 GMT ...
>>No. You didn't really even need the FindRacer class. Anonymous methods >>are really useful when dealing with predicates. For example, instead of: [quoted text clipped - 9 lines] >> >>without having to declare any new class at all. But if I had defined:
public class RacerCollection : List<Racer> { }
Why can't I do:
RacerCollection theList3 = racers.FindAll(delegate(Racer racer) { return racer.Car == "Ferrari"; });
Both are List collections of Racer.
But where this will work:
List<Racer> theList = racers.FindAll(delegate(Racer racer) { return racer.Car == "Ferrari"; });
Why doesn't the other work? The only difference being "RacerCollection" vs "List<Racer>". Yet both are handled the same way and have the same methods.
Thanks,
Tom
Jon Skeet [C# MVP] - 20 Feb 2008 18:59 GMT > >>without having to declare any new class at all. > [quoted text clipped - 6 lines] > RacerCollection theList3 = racers.FindAll(delegate(Racer racer) { return > racer.Car == "Ferrari"; }); Because List<T>.FindAll returns a List<Racer>, not a RacerCollection.
> Both are List collections of Racer. Sure - but what if you'd got other information in RacerCollection - where would you expect List<T> to get that information from when building a RacerCollection to return?
> But where this will work: > [quoted text clipped - 3 lines] > Why doesn't the other work? The only difference being "RacerCollection" vs > "List<Racer>". Yet both are handled the same way and have the same methods. That doesn't mean they're the same type.
If I do:
class First {}
class Second {}
that doesn't mean I can do:
First f = new First(); Second s = f;
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
tshad - 24 Feb 2008 21:44 GMT >> >>without having to declare any new class at all. >> [quoted text clipped - 27 lines] > > That doesn't mean they're the same type. But RacerCollection inherits the List<Racer>.
I am not sure why I would do this then:
public class RacerCollection : List<Racer> { }
I see this done in other places. Does this mean I would have to do both?
public class RacerCollection : List<Racer> { } List<Racer> racers = new List<Racer>();
and then do RacerCollection.Add and racers.Add so I can use both objects?
If I have already created my object as RacerCollection and then decide that I want to do a FindAll - do I have to do it all over again with List<racers> just to be able use FindAll?
Or is it that I can use RacerCollection, but only the result has to be List<Racer>:
public class RacerCollection : List<Racer> { } RacerCollection racers = new RacerCollection();
List<Racer> result = racers.Findall(...);
Thanks,
Tom
Jon Skeet [C# MVP] - 24 Feb 2008 22:19 GMT > > That doesn't mean they're the same type. > > But RacerCollection inherits the List<Racer>. Yes - not the other way round. Every RacerCollection is a List<Racer>, but not every List<Racer> is a RacerCollection.
> I am not sure why I would do this then: > [quoted text clipped - 6 lines] > > and then do RacerCollection.Add and racers.Add so I can use both objects? It's not at all clear what you mean by RacerCollection.Add - unless you've created a static method.
> If I have already created my object as RacerCollection and then decide that > I want to do a FindAll - do I have to do it all over again with List<racers> > just to be able use FindAll? No, you've got it the wrong way round. You can call FindAll on a RacerCollection just fine.
> Or is it that I can use RacerCollection, but only the result has to be > List<Racer>: [quoted text clipped - 3 lines] > > List<Racer> result = racers.Findall(...); Exactly. How would the code in List<T>.FindAll know how to create a new instance of RacerCollection? There might be constructors which take particular parameters, etc.
All it knows how to build is instances of List<T> - so that's what FindAll does.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Peter Duniho - 20 Feb 2008 20:03 GMT > [...] >> Well, it doesn't. "theList" is an instance of List<Racer>, and it only [quoted text clipped - 6 lines] > > Obviously, this is not the case. Well, if it were obvious I think maybe you wouldn't have asked the question. :) But yes, your assumption was incorrect. List<T> doesn't inherit any methods from the type in the collection. Nor would any generic class inherit any methods from the generic type parameter's class. You would always need to get an instance of that type parameter to get at a method in that class.
>> If you want to use the GetCar() method as the predicate, you need to a) >> have a list that contains strings rather than Racers (since the method's [quoted text clipped - 4 lines] > collection. If I was only going to use strings, why not use an Array > class. Why not indeed? :)
My comment was only with respect to the prerequisites for getting the code you posted to actually work. I never meant to suggest you'd _want_ to approach your solution that way.
> [...] >> List<Racer> theList = racers.FindAll(delegate(Racer racer) { return [quoted text clipped - 7 lines] > be a > really good place. There are lots of reasons to use delegates. They come up in a wide variety of situations in .NET. The Predicate<T> delegate type is just one example, and as you've seen it's very useful for the various "find" methods on the generic classes. But they're used for event handlers (which if you've done any GUI, you are almost certainly using), callbacks (which are often used when doing things asynchronously, in a multi-threaded design), and other scenarios.
Pete
Jon Skeet [C# MVP] - 20 Feb 2008 20:12 GMT <snip>
> There are lots of reasons to use delegates. They come up in a wide > variety of situations in .NET. The Predicate<T> delegate type is just one [quoted text clipped - 3 lines] > (which are often used when doing things asynchronously, in a > multi-threaded design), and other scenarios. LINQ in particular uses delegates extensively. Even if you're(*) not using LINQ now, it's worth becoming familiar on delegates so it's less of a shock when you do :)
(*) General "you", not Peter in particular. Using "one" just sounds pretentious.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Peter Duniho - 20 Feb 2008 20:26 GMT > [...] > (*) General "you", not Peter in particular. Using "one" just sounds > pretentious. Really? I use "one" reasonably regularly, mainly so I can avoid having to footnote comments I might make with clarifications that I'm not talking about a specific person. :)
I didn't realize I was sounding pretentious. Oh well.
Pete
Jon Skeet [C# MVP] - 20 Feb 2008 20:32 GMT > > [...] > > (*) General "you", not Peter in particular. Using "one" just sounds [quoted text clipped - 5 lines] > > I didn't realize I was sounding pretentious. Oh well. In some cases it's fine - but in this case I figured it sounded weird and pretentious to me. Besides, I like footnotes :)
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
tshad - 24 Feb 2008 21:49 GMT > There are lots of reasons to use delegates. They come up in a wide > variety of situations in .NET. The Predicate<T> delegate type is just one [quoted text clipped - 3 lines] > (which are often used when doing things asynchronously, in a > multi-threaded design), and other scenarios. I agree that there are many reasons to use them.
I am still trying to get my mind around some of the uses as some of the examples I see, use a delegate when you can just call the same function directly and I see no reason why they use the delegate there.
I can see why you would use it in a callback situation.
Thanks,
Tom
Peter Duniho - 24 Feb 2008 23:34 GMT > I agree that there are many reasons to use them. > > I am still trying to get my mind around some of the uses as some of the > examples I see, use a delegate when you can just call the same function > directly and I see no reason why they use the delegate there. I can't comment without a specific example. But I would agree that if there's a straightforward way to write the code with the method being called directly rather than through a delegate, then doing so is preferable to using a delegate.
Delegates are useful, but they definitely can obfuscate what's going on, depending on the situation. You're right to think that if the delegate is not needed, then it usually will make sense not to use one.
Pete
tshad - 24 Feb 2008 21:15 GMT > I am confused as to why you need to use Predicate<t> in a findall method > of > Generics. I suppose that depends on your definition of "use". The parameter for the FindAll() method is a Predicate<T>, so you must use some instance of an appropriate Predicate<T>.
But type inference can take a method name and convert it to the necessary instance without explicitly writing "Predicate<T>", so in that sense you don't need to use Predicate<T> in a call to the FindAll() method.
> [...] > But for Racers, I do the FindAll method with: [quoted text clipped - 7 lines] > > Why is that? Because the second example takes advantage of type inference. You should be able to get the first example to work fine in a similar way:
List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);
> Also, I tried set up 2 predicates similar to the GetDino method and put > the [quoted text clipped - 8 lines] > 'System.Collections.Generic.List<Generics.Racer>' does not contain a > definition for 'GetCar' Well, it doesn't. "theList" is an instance of List<Racer>, and it only contains the methods declared in the generic List<T> class. Where would it get the GetCar() method from?
If you want to use the GetCar() method as the predicate, you need to a) have a list that contains strings rather than Racers (since the method's argument is a string not a Racer), and b) reference the method from an instance of Racer, not from an instance of List<T>.
> but the class Racer does contain it. Yes, which is why you need an instance of Racer, not an instance of List<Racer>.
> Do you have to create a whole new class (as I do with FindRacer) to get > this > to work? No. You didn't really even need the FindRacer class. Anonymous methods are really useful when dealing with predicates. For example, instead of:
FindRacer finder = new FindRacer("Ferrari"); List<Racer> theList = racers.FindAll(finder.DrivingCarPredicate);
with all of the overhead of declaring that FindRacer class, you could have just used:
List<Racer> theList = racers.FindAll(delegate(Racer racer) { return racer.Car == "Ferrari"; });
without having to declare any new class at all.
Pete
tshad - 24 Feb 2008 21:45 GMT Sorry the other message got sent by accident.
I am not sure why OutlookExpress won't put the ">" in front of your responses and I have to put them there myself. Is there something in your newreader that would prevent that?
>> I am confused as to why you need to use Predicate<t> in a findall method >> of [quoted text clipped - 7 lines] >instance without explicitly writing "Predicate<T>", so in that sense you >don't need to use Predicate<T> in a call to the FindAll() method. Then what is a Predicate<T>?
How do I know if am passing an object of Predicate<T>?
Thanks,
Tom
Peter Duniho - 24 Feb 2008 23:39 GMT > Sorry the other message got sent by accident. > > I am not sure why OutlookExpress won't put the ">" in front of your > responses and I have to put them there myself. Is there something in > your > newreader that would prevent that? I'm not sure. You're the first person to have mentioned that problem. What version of OE are you using? I used to use it, and never ran into an issue with it failing to quote text properly. But I can't rule out that there's something about the formatting of the messages I post that is causing it some problem.
Unfortunately, not knowing what that might be, I'm at a loss as to how I might fix it on my end.
> [...] >> But type inference can take a method name and convert it to the [quoted text clipped - 3 lines] > > Then what is a Predicate<T>? I'm not sure what you're asking. The MSDN docs describe the type here: http://msdn2.microsoft.com/en-us/library/bfcke1bz(vs.80).aspx
Is there something about that that doesn't answer the question?
> How do I know if am passing an object of Predicate<T>? If the method's argument is Predicate<T> and it compiles without an error, then you are passing a Predicate<T>.
Pete
tshad - 25 Feb 2008 21:35 GMT >> Sorry the other message got sent by accident. >> [quoted text clipped - 11 lines] > Unfortunately, not knowing what that might be, I'm at a loss as to how I > might fix it on my end. I remember looking into this before and it was how the other persons reader was sending the message. Can't remember what the problem was. I only have this problem very rarely.
I am using OE 6.
Tom
>> [...] >>> But type inference can take a method name and convert it to the [quoted text clipped - 15 lines] > > Pete Peter Duniho - 25 Feb 2008 22:07 GMT >>> I am not sure why OutlookExpress won't put the ">" in front of your >>> responses and I have to put them there myself. Is there something in [quoted text clipped - 10 lines] > have > this problem very rarely. Hmmm...
I just sent email to you saying that I'd checked and on my computer OE behaves fine. But with your more recent explanation that it only happens some times, I took another look. And yes, for some messages I can in fact reproduce the problem.
One difference between messages that quote correctly and those that don't is that those that do have "Content-Transfer-Encoding: 7bit" in the header, while those that don't have "Content-Transfer-Encoding: Quoted-Printable". In the latter case, the message is also filled with '='-quoted characters (but not in a way that I recognize...the message shows fine in newsreaders though, so I assume it's at least legal encoding
:) ). Oddly, both have UTF-8 described in the "Content-Type" field. So maybe there's a difference in terms of what characters are actually being posted. Maybe if the message includes only ASCII characters, it works fine, but as soon as something that doesn't fit in ASCII is included, the "Content-Transfer-Encoding" changes. Unfortunately for that theory, I don't actually see anything in any of the messages I checked that couldn't be represented in regular ASCII. It's not really clear to me what might be causing the difference.
So, I think it's for sure either a bug in Opera (what I'm using as a newsreader) or Outlook Express (what you're using). But I don't have a good guess as to which is actually the case. Could be either. For that matter, I suppose it could be both. :)
Unfortunately, I don't really know enough about the various character encoding techniques used for text messages to really understand the problem well enough to suggest a conclusive reason for why it happens, never mind how it might be fixed.
Pete
Peter Duniho - 25 Feb 2008 22:42 GMT > [...] > Unfortunately, I don't really know enough about the various character > encoding techniques used for text messages to really understand the > problem well enough to suggest a conclusive reason for why it happens, > never mind how it might be fixed. Okay, sorry for the off-topic again, but I think I've answered at least part of the question.
I don't know why "quoted-printable" is being used as the format. Presumably Opera is seeing something in the message that it feels justifies the use of "quoted-printable". What that might be, I have no idea. The only quoted characters in the message are soft line-breaks (an '=' character followed by an actual line-break) and characters where '=' is in the actual text (i.e. they are being quoted because the '=' is the quoting character).
If I had to guess, I'd say it's probably related to the line lengths, with Opera wanting to use "quoted-printable" as a way to put line-breaks in the message that don't actually force a line-break. Maybe some sort of interaction between the line-breaks as the message was composed versus the line-breaks Opera imposes for the purpose of limiting line-lengths for message.
However, in any case looking at the message it appears to me that Opera is not using an invalid format. The formatting is weird, but not wrong. OE should be interpreting the "quoted-printable" encoding correctly, and in fact it does when it's displaying the message. It just isn't handling it correctly when it goes to quote the text in a reply.
I'll see if there's a setting in Opera that allows more fine-grained control over what's going on, that would allow me to post messages in the same way without OE's bug manifesting itself. But, given that it's a bug in your newsreader and not mine, I don't plan to spend much time on it. :)
Anyway, I think that's enough of this tangent here. I'm happy to discuss it further via email if you like, but out of respect for the newsgroup topic this'll be my last message to the newsgroup on the issue.
Pete
tshad - 26 Feb 2008 02:25 GMT > [...] I'm not sure I understand the problem, either. But I did find the message I sent a while ago about the problem and the response:
This is caused when the message to which you're replying was sent using Quoted Printable format. Nothing you can do about it, short of installing OE-QuoteFix: http://home.in.tum.de/~jain/software/oe-quotefix/
 Signature ~Robear Dyer (PA Bear) MS MVP-Windows (IE, OE, Security, Shell/User) AumHa VSOP & Admin; DTS-L.org
tshad wrote:
> Looking at Newgroups and hitting replies normally puts a ">" in front of > the [quoted text clipped - 12 lines] > > Tom Not sure I can do much about it, according to Robert. I will look at the fix he mentioned. Looks pretty good, though.
I agree that th is off topic.
Just thought I would let you know.
Thanks,
Tom
Peter Duniho - 26 Feb 2008 03:40 GMT > I'm not sure I understand the problem, either. But I did find the > message I [quoted text clipped - 4 lines] > installing > OE-QuoteFix: http://home.in.tum.de/~jain/software/oe-quotefix/ Okay, I know I said I wasn't going to add any more to the thread. But I just had to share this: http://support.microsoft.com/kb/q168779/
So, Microsoft calls this a "side-effect", and incorrectly claims that "The main purpose of 'Plain Text, Quoted Printable' format is to allow for line wrapping".
Sheesh. I mean, I'm normally a reasonably staunch defender of Microsoft and their products, but when I read stuff like this KB article, it's not hard to see how people start getting the impression that someone over there isn't operating with all of their marbles, that they aren't the sharpest knife in the drawer, that the lights are on but no one's home, that..
Oh well. At least there's a "fix". And if you don't like the "OE-QuoteFix" utility, you have a number of other good newsreaders on Windows to choose from. :)
Pete
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|