OSG Community College C# for Programmers Class #7 Log 03/24/2009
Pastebins are pasted at the bottom:
[12:06] Snowdrop Short: hi Starky
[12:06] Snowdrop Short: I haven't read that one
[12:06] M1sha Dallin: examples (or the lack) seems good
[12:06] Adelle Fitzgerald: hiya Starky
[12:06] M1sha Dallin: Hi Starky
[12:07] Snowdrop Short: I've been using C# for so long now, that I
hardly ever read anything about the language as such
[12:07] M1sha Dallin: :-)
[12:08] Snowdrop Short: sometimes I use google, if I run into trouble
[12:08] Starky Rubble: which one M1sha?
[12:08] M1sha Dallin: C# 3.0 in a Nutshell
[12:08] M1sha Dallin: an O'Reilly Quick Reference
[12:08] Starky Rubble: O'Rielly nutshells were always good :)
[12:09] M1sha Dallin: it's nearly 900 pages - so not that quick :-)
[12:09] M1sha Dallin: but helpful when you know what you are looking
for
[12:09] Snowdrop Short: be carefull about lambda's though
[12:09] M1sha Dallin: I haven't read that bit
[12:09] Snowdrop Short: the scoping rules of that seems pretty
"hackish" to mee
[12:10] Snowdrop Short: never assume they work the way you expect
them to
[12:10] Snowdrop Short: but that's the topic for some later class
[12:10] Snowdrop Short: tonight's topic will be generics
[12:10] M1sha Dallin: I currently don't expect anything to work the
way I hope :-)
[12:11] Snowdrop Short: ok
[12:11] Snowdrop Short: I have some code, I'd like to present to you
[12:11] Snowdrop Short:
http://www.pastebin.ca/1370864
[12:12] Snowdrop Short: give me your best guess as to what you think
the gibberish means
[12:12] Starky Rubble: I is for waht... i forget - Instance?
[12:13] M1sha Dallin: A static method Max defined generically
[12:13] Snowdrop Short: interface
[12:13] Starky Rubble: there you go
[12:13] Starky Rubble: a naming rule as I remember
[12:13] M1sha Dallin: the type will be defined by its instatiation
[12:13] Snowdrop Short nods, the I in IConparable is just a
convention
[12:14] Snowdrop Short: ok
[12:14] Snowdrop Short: so let me ask you a couple of questions
[12:15] Snowdrop Short: internal static T Max<T>(T a, T b) where T :
IComparable
[12:15] Snowdrop Short: what does the internal mean
[12:15] Snowdrop Short: and why is it tbere
[12:16] M1sha Dallin: its the access modifier
[12:17] Snowdrop Short nods, and why did I choose "internal" and not
"public", "private" or "protected"?
[12:17] M1sha Dallin: somewhere between public and private - only
available to the class that inherits?
[12:17] Starky Rubble: right
[12:18] Snowdrop Short: M1sha, thats "protected"
[12:18] Starky Rubble: oops
[12:18] Snowdrop Short: I chose "internal"
[12:18] M1sha Dallin: :-)
[12:19] Snowdrop Short: what did I gain by using "internal", as you
might recall, "internal" means "accessible inside the same namespace"
[12:19] M1sha Dallin: ok
[12:19] Starky Rubble: oh right
[12:20] Snowdrop Short: ok
[12:21] Snowdrop Short: I wanted to restrict access to the Max method
to the greatest extent, but still make it possible to access the
method from inside Main in MainClass
[12:21] Starky Rubble: right
[12:21] Snowdrop Short: had I chosen "public" .. it whould have been
accessible by every one
[12:21] M1sha Dallin: In this instance why? It's a useful function
[12:21] Snowdrop Short: "private" was out because that would prevent
me from accessing it
[12:22] Snowdrop Short: protected was out too, because "MainClass"
does not inherit from Tools
[12:22] Snowdrop Short: actually the framework already has one, in
the Math namespace
[12:22] Snowdrop Short: but I wanted it here, because it is a very
minimal example of generics
[12:23] M1sha Dallin: ok
[12:23] Starky Rubble: right
[12:23] Starky Rubble: the comaparables are not of specified type
[12:23] Snowdrop Short: and I wanted to use the most restrictive
access
[12:23] Snowdrop Short: next ... "static"
[12:24] M1sha Dallin: a class rather than an instance method
[12:24] Starky Rubble: yes
[12:24] Snowdrop Short: yes, that way I can access the method,
without creating an instance of the Tools class
[12:25] Snowdrop Short: and there really isn't a need for an
instance, since "Tools" kind of implies that they do their job, and
then exit, kind of like a function
[12:25] Starky Rubble: ok
[12:25] Snowdrop Short: now on to the mystery
[12:26] Snowdrop Short: T Max<T>(T a, T b)
[12:26] M1sha Dallin: Method Max - returning an instance of type T
[12:26] Snowdrop Short: Max ... makes sense for a lot of different
datatypes
[12:26] M1sha Dallin: taking two parameters a and b also of type T
[12:26] Snowdrop Short: integers, floats, decimals, dates, strings
[12:27] M1sha Dallin: T is constrained by the where clause?
[12:27] Snowdrop Short: so I wanted to create a function which made
sense, no matter if it worked on "strings" or on "integer" or almost
any other kind
[12:28] Snowdrop Short: the only limit is that is should make sense
to ask the question "what is the greater of the two?"
[12:28] Snowdrop Short: sometimes that doesn't make sense
[12:28] Snowdrop Short: e.g. colors
[12:29] Snowdrop Short: the Max function as written here, will work
for almost any datatype
[12:29] Snowdrop Short: since I didn't know the datatype, I used a
"variable" for the type
[12:29] Snowdrop Short: and called it "T"
[12:30] Jos Joszpe is Online
[12:30] Snowdrop Short: so, T gets replaced with the real type
[12:30] Snowdrop Short: when the Max method is actually used
[12:31] Snowdrop Short: well, what happens is that the compiler sees
the call to the Max method, and creates the correct code during
compilation
[12:31] Snowdrop Short: so if you look at line 17
[12:32] Snowdrop Short: Tools.Max<int>(2,05)
[12:32] Snowdrop Short: is the interesting part
[12:32] Jos Joszpe is Online
[12:32] Snowdrop Short: <int> tells the compiler that for now "Max"
should work on integers
[12:33] Adelle Fitzgerald: so in line 18, because there is no
datatype defined, what does it default to? string?
[12:33] Starky Rubble: yep
[12:33] Snowdrop Short: we pass the actual type inside the angle
braces
[12:33] Snowdrop Short: Tools.Max("2","05")
[12:33] Snowdrop Short: that's actually a very very good question
[12:34] Starky Rubble: heh
[12:34] Snowdrop Short: the thing is ... the compiler does what is
called "type inference"
[12:34] Adelle Fitzgerald: from what i can tell, its seeing !2!,"05"
as a string, but is that because for the double quotes that is sees is
as string?
[12:34] Snowdrop Short: it sees the two strings used as paramers to
the method
[12:34] Adelle Fitzgerald: oops, i mean "2","05"
[12:35] Snowdrop Short: and then "infers" that in this situation, it
makes sense to use the "string" version
[12:35] Snowdrop Short: or .. guesses, is another word for it
[12:35] Adelle Fitzgerald: gotcha
[12:35] Adelle Fitzgerald: but in good practice, you should still
define is as a string though?
[12:35] Snowdrop Short: Tools.Max<string>("2","05")
[12:36] Snowdrop Short: would have been perfectly legal
[12:36] Adelle Fitzgerald nods
[12:36] Snowdrop Short: but since the compiler can guess from the
useage, it isn't needed
[12:36] Snowdrop Short: whether you want to specify "<string>" or not
[12:37] Snowdrop Short: is a matter of taste
[12:37] Adelle Fitzgerald: gotcha
[12:37] Snowdrop Short: personally I think the anglebraces look kind
of ugly
[12:37] Snowdrop Short: but it helps clarify what is going on
[12:38] Adelle Fitzgerald: i do prefer normal brackets myself
[12:38] Snowdrop Short: so on to the next mystery
[12:38] Snowdrop Short: where T : IComparable
[12:39] robert omegamu is Offline
[12:39] M1sha Dallin: type T must have comparison operations defined?
[12:39] M1sha Dallin: <, >, == etc.
[12:39] Snowdrop Short: well, yes
[12:39] Starky Rubble: IComparable has code that will allow T?
[12:39] Starky Rubble: or not
[12:39] Snowdrop Short: it is a way of restricting what kind of
"parameters" can be used as the actual type
[12:39] robert omegamu is Online
[12:40] Snowdrop Short: it says that T must implement the "interface"
called IComparable
[12:40] Snowdrop Short: so in order to understand what goes on
[12:40] Snowdrop Short: we need to look at interfaces
[12:40] Starky Rubble: ok
[12:41] Snowdrop Short: so lets go back to our talk about
intheritance and "polymorphism"
[12:41] Jos Joszpe is Online
[12:42] Marcus Llewellyn is Online
[12:42] Snowdrop Short: remember that we talked about classes and
subclasses
[12:42] Snowdrop Short: and that a class could only inherit from one
other class
[12:42] Starky Rubble: yes
[12:42] Snowdrop Short: no "multiple" inheritance
[12:43] Snowdrop Short: we talked about a class called "Animal"
[12:43] Snowdrop Short: and that there could be a subclass called
"WingedAnimal"
[12:43] Snowdrop Short: and another one called "Mamal"
[12:43] Snowdrop Short: both inheriting from Animal
[12:44] Snowdrop Short: but "Bat", couldn't inherit from both, so
either it was a Mamal or a WingedAnimal
[12:44] Snowdrop Short: but not both
[12:44] Starky Rubble: right
[12:45] Snowdrop Short: interfaces are a way to provide multiple
shapes to the same class
[12:45] Snowdrop Short: Bat could have the "shape" Animal" or "Mamal"
or ... even "object"
[12:45] Snowdrop Short: the default base one, everyone has
[12:46] Snowdrop Short: interfaces can be used to give more shapes to
a class
[12:46] Snowdrop Short: take a look here:
[12:46] Snowdrop Short:
http://msdn.microsoft.com/en-us/library/system.icomparable(VS.80).aspx
[12:48] Snowdrop Short:
http://www.pastebin.ca/1370895
[12:49] Snowdrop Short: maybe this one is better
[12:49] Snowdrop Short:
http://www.pastebin.ca/1370896
[12:49] Snowdrop Short: I just removed the "abstract" predicate
[12:49] Snowdrop Short: it wasn't really needed
[12:50] Snowdrop Short: interfaces are always abstract
[12:50] Snowdrop Short: if you look at the pastebin
[12:50] Snowdrop Short: you'll see it looks very much like a class
definition
[12:50] Snowdrop Short: except it has "interface" instead of "class"
[12:51] Snowdrop Short: and there is no body
[12:51] Snowdrop Short: { ... code .... }
[12:51] Snowdrop Short: in a way you can think of it as a contract
[12:52] Snowdrop Short: if you looke at the Temperature class from
the msdn site url I gave you
[12:52] Snowdrop Short: it is a promise that the "Temperature" class
will implement all the methods defined in the "IComparable" interface
[12:53] Snowdrop Short: if it doesn't .. the compiler will complain
[12:54] Starky Rubble: ok
[12:54] Snowdrop Short: in this case, the only method which needs to
be implemented, is "CompareTo"
[12:55] Snowdrop Short: remember the handles, we used to hold on to
an object
[12:55] Snowdrop Short: and how we in the group sample
[12:55] Snowdrop Short: used different types of handles
[12:55] M1sha Dallin: :-) The Celsius method is wrong
[12:55] Snowdrop Short: "GroupBase"
[12:55] Snowdrop Short: "Group"
[12:55] Snowdrop Short: and even
[12:55] Snowdrop Short: "object"
[12:56] Snowdrop Short: IComparable can be used as the type of a
handle as well
[12:56] Snowdrop Short: so I can assign any object implementing
IComparable to a handle of that type
[12:57] Snowdrop Short: what is the problem with "Celecius" except
that it is a bit impresise "2" ??
[12:57] Starky Rubble: 9/5 is pretty close lol
[12:57] M1sha Dallin: It's a bit imprecise
[12:58] M1sha Dallin: water boils at 90C according to the conversion
[12:58] Snowdrop Short smiles
[12:58] Snowdrop Short: ok .. so it is correct at the top of Mount
Everest :-)
[12:58] Snowdrop Short smiles
[12:58] M1sha Dallin: half way maybe :-)(
[12:59] Snowdrop Short: ok
[12:59] Starky Rubble: as long as we are not coding an egg timer...
[13:00] Snowdrop Short: in this case I chose "IComparable" because it
is the generic way in .Net/Mono to say that < > >= <= and == should
make sense and be implemented
[13:01] Snowdrop Short: compareto takes to things and compares them
and returns an integer based on the result of comparing the two
[13:01] Snowdrop Short: A 32-bit signed integer that indicates the
relative order of the objects being compared. The return value has
these meanings:
[13:01] Snowdrop Short: less than 0
[13:02] Snowdrop Short: means that "this < object"
[13:02] Snowdrop Short: greater than 0
[13:02] Snowdrop Short: means that "this > object"
[13:02] Snowdrop Short: and 0 means
[13:02] Snowdrop Short: "this == object"
[13:03] Snowdrop Short: a lot of the standard types in c# implements
this interface
[13:03] Snowdrop Short: ints, strings, dates, floats .. and a lot of
other
[13:03] Snowdrop Short: if you create your own class, you can
implement IComparable
[13:04] Snowdrop Short: and that way other classes will know how to
sort your objects
[13:04] Snowdrop Short: e.g. in "SortedList"
[13:04] Snowdrop Short: going back to my original code sample
[13:04] Snowdrop Short:
http://www.pastebin.ca/1370864
[13:05] Snowdrop Short: I defined a restriction on the types that can
replace the "T"
[13:05] Snowdrop Short: they *must* implement the interface
"IComparable"
[13:05] Starky Rubble: right
[13:05] Snowdrop Short: meaning that both I and the compiler knows
that the method "CompareTo" can be used
[13:05] Snowdrop Short: now the next oddity
[13:05] Snowdrop Short: return a.CompareTo(b)>0 ? a : b;
[13:06] Snowdrop Short: what does that mean?
[13:06] Snowdrop Short: a.CompareTo(b)>0
[13:06] Starky Rubble: a is the 'this' b is 'object'
[13:07] Snowdrop Short nods, and that is valid and legal because of
the "where thingie"
[13:07] Snowdrop Short: so a.CompareTo(b)
[13:07] Snowdrop Short: returns an integers, based on which is the
greater of the two
[13:08] Snowdrop Short: next is the construct "xxx?a:b"
[13:08] Snowdrop Short: that is a kind of short hand way of saying
"if xxxx then a else b"
[13:09] Snowdrop Short: when used the right way, it helps keep the
size of the code down
[13:09] Snowdrop Short: used the wrong way, it makes the code
completely unreadable
[13:09] Starky Rubble: right
[13:09] Snowdrop Short: especially if you nest the ":?" as you
sometimes do with if's
[13:10] Snowdrop Short: personally, I think it is ok to use :? is
this limited way
[13:10] Snowdrop Short: but that's my personal opinion
[13:10] Snowdrop Short: others will disagree with me
[13:10] Snowdrop Short: and definatetely :? can make the code harder
to read
[13:11] Snowdrop Short: so "return a.CompareTo(b)>0 ? a : b;!
[13:11] Snowdrop Short: says if a is grether than b then return a
else return b
[13:11] Starky Rubble: right
[13:12] Snowdrop Short: ok
[13:12] Snowdrop Short: we just spent an hour
[13:12] Snowdrop Short: digging into the gory details of this method
[13:12] Snowdrop Short: which most of us could understand by scanning
it
[13:12] Snowdrop Short: but .. hopefully now we know a bit more about
how generics works
[13:13] Starky Rubble: yes
[13:13] Snowdrop Short: ok ...
[13:13] Snowdrop Short: so this is what is called a generic method
[13:14] Snowdrop Short: sometimes you don't need a restriction on the
datatype to be used
[13:14] Snowdrop Short: so "where T....."
[13:14] Snowdrop Short: is optional
[13:14] Snowdrop Short: in my case, I needed it to have access to
"CompareTo"
[13:14] Snowdrop Short: but a lot of other things can be generic
[13:14] Snowdrop Short: classes
[13:14] Snowdrop Short: interfaces
[13:15] Snowdrop Short: delegates
[13:16] Snowdrop Short: lets take a look at a generic class
[13:18] Snowdrop Short:
http://www.pastebin.ca/1370921
[13:18] Snowdrop Short: let me know when you have it
[13:18] Starky Rubble: ok
[13:18] M1sha Dallin: ok
[13:19] Adelle Fitzgerald: got it
[13:19] Snowdrop Short: ok
[13:19] Snowdrop Short: the big change is that I have moved the "<T>
where T : IComparable"
[13:19] Snowdrop Short: up to the definition of the class
[13:19] Snowdrop Short: and removed it from the methods
[13:19] Starky Rubble: right
[13:20] Snowdrop Short: and I removed the <T> from Max
[13:20] Snowdrop Short: since it is no longer a generic method
[13:20] Snowdrop Short: but a method in a generic class
[13:20] Snowdrop Short: and I took the opportunity to add a "Min"
method as well
[13:20] Snowdrop Short: and then
[13:20] Snowdrop Short: in line 23
[13:21] Snowdrop Short: Tools<string>.Max("2","05")
[13:21] Snowdrop Short: I added <string>
[13:21] Snowdrop Short: because type inference doesn't work on
classes
[13:21] Snowdrop Short: only on methods
[13:22] Starky Rubble: ok
[13:22] Snowdrop Short: so I had to specifically state that the Tools
variant should be of the "variant" "string"
[13:23] Snowdrop Short: other than that.. it is just as we'd expect
it to be
[13:23] Snowdrop Short: no big change between generic methods and
generic classes
[13:23] Snowdrop Short: ok
[13:23] Snowdrop Short: so now we should be fully equipped to
understand a declaration like
[13:24] Snowdrop Short: "List<GroupBase> grops;
[13:24] Snowdrop Short: and all our other generic collections
[13:25] Snowdrop Short: because that's exactly the tools used to
implement them
[13:25] Snowdrop Short: ok, questions so far?
[13:26] Starky Rubble: no
[13:26] M1sha Dallin: nope
[13:26] Snowdrop Short: so, you are ok with generics?
[13:27] Adelle Fitzgerald: umm, i think so
[13:27] M1sha Dallin: fine until I try and use them - but have had
some success :-)
[13:27] Snowdrop Short: ok
[13:27] Snowdrop Short: so far we've looked at a generic with only
one unknown type
[13:28] Snowdrop Short: but it is perfectly legal to have multiple
[13:28] Snowdrop Short: or use more meaning full names than simply
"T"
[13:28] Snowdrop Short: so "class Tools<T,U,V,W>"
[13:29] Snowdrop Short: would be perfectly legal
[13:29] Starky Rubble: ok
[13:31] Adelle Fitzgerald: crashed?
[13:31] Snowdrop Short: lets
[13:31] Adelle Fitzgerald: oh hehe
[13:32] Snowdrop Short: take a look at some of the things which can
be specified in the where clause
[13:32] Snowdrop Short: it doesn't have to be only intefaces
[13:32] Snowdrop Short: it could be classes as well
[13:33] Snowdrop Short: so you could say that the type should inherit
from some class
[13:33] Snowdrop Short: and then there is the special
[13:33] Snowdrop Short: where T: new()
[13:34] Snowdrop Short: which is a way of saying that it should be
possible to create a new instance of the the type using
[13:34] Snowdrop Short: new T();
[13:34] Snowdrop Short: without any parameters
[13:34] Starky Rubble: hmmm
[13:34] Starky Rubble: ok
[13:35] Snowdrop Short: a constructor which doesn't take any
parameters is sometimes a requirement
[13:35] Snowdrop Short: becuse how else can you create an instance,
if you don't know the slightest bit about the class you're trying to
create an instance of
[13:36] Snowdrop Short: you wouldn't know which paramters to pass, or
what values to use for the parameters
[13:36] Snowdrop Short: there is one more restriction which can be
made
[13:37] Snowdrop Short: unfortunately we haven't got everything in
place to understand the meaning
[13:38] Snowdrop Short: you see
[13:38] Snowdrop Short: I haven't bee completely honest to you
[13:38] Snowdrop Short: when I said that everything in c# is a class
[13:38] Snowdrop Short: there is a bit of nuance I've left out
[13:39] Snowdrop Short: somethings are only "semi classes"
[13:39] Snowdrop Short: called "value types"
[13:39] Snowdrop Short: ints, bytes, chars, floats, dates
[13:39] Snowdrop Short: are value types
[13:40] Snowdrop Short: not full blown classes
[13:40] Snowdrop Short: and it is possble to specifcy that the type
of T should be a full blown class
[13:40] Snowdrop Short: by specifying "where T: class"
[13:40] Snowdrop Short: or "where T: struct"
[13:41] Snowdrop Short: for the more simple value types
[13:41] Snowdrop Short: note that "strings" are fullblown classes
[13:42] Snowdrop Short: while a "char" is a value type
[13:42] Starky Rubble: thus no direct conversion
[13:42] Snowdrop Short: the difference between value types and
classes has to do with how and where in memory they reside
[13:43] Snowdrop Short: but besided the fact that you can assign the
value "null" to a class handle, but not to the handle of a value type
[13:43] Snowdrop Short: you hardly notice any difference
[13:44] Snowdrop Short: so I have left out that part, until we have
more theory in place
[13:44] Snowdrop Short: ok
[13:45] Snowdrop Short: that's about what I had on the agenda for
today
[13:45] M1sha Dallin: ok
[13:45] Snowdrop Short: I've got a bit of nasty homework for you
[13:45] Widget Whiteberry is Online
[13:45] M1sha Dallin: I was just going to ask :-)
[13:45] Snowdrop Short: remember our talk about "internal"
[13:46] Snowdrop Short: at the start
[13:46] M1sha Dallin: yep
[13:46] Snowdrop Short: and our talk last week about how "private" is
the default
[13:46] Starky Rubble: yes
[13:46] Widget Whiteberry is Offline
[13:47] Snowdrop Short: but that would mean that the class "Tools" is
really marked with a default attribute of private
[13:47] Snowdrop Short: and so is "MainClass"
[13:47] Snowdrop Short: isn't it?
[13:47] Snowdrop Short: so if Tools is really marked a "private"
[13:48] Snowdrop Short: then how come I can see it inside "MainClass"
[13:48] Snowdrop Short: ?
[13:48] Snowdrop Short: and where can I see the class
[13:48] Snowdrop Short: and where is it invisible?
[13:49] Snowdrop Short: so I want you to experiment with classes in
different namespaces
[13:49] Snowdrop Short: and discover where you can access the Tools
class from
[13:49] Snowdrop Short: and where not
[13:49] Starky Rubble: ok
[13:50] M1sha Dallin: ok
[13:50] Snowdrop Short: so you'll need to write a number of classes,
in different namespaces, and try to access it in different
[13:50] Snowdrop Short: access "Tools" in different situations
[13:50] Snowdrop Short: and then ... if you have time
[13:51] Snowdrop Short: visit the group class
[13:51] Snowdrop Short: and implement generic collections
[13:51] Starky Rubble: mm hmmm...
[13:51] Starky Rubble: heh
[13:51] Starky Rubble: cool
[13:51] Snowdrop Short: now we have all the tools in place to do that
[13:51] Snowdrop Short: ok ... time for bed for me
[13:51] Starky Rubble: ok
[13:51] Snowdrop Short: well... a little break and then bed :-)
[13:52] M1sha Dallin: ty - goodnight Snowdrop
[13:52] Snowdrop Short: likewise :-)
[13:52] Starky Rubble: bye... and thanks again
[13:52] Adelle Fitzgerald: thanks Snowdrop, sleep well :)
[13:52] Snowdrop Short: and remember, I'm on IRC if you run into
trouble
[13:52] Snowdrop Short: nite
[13:52] Adelle Fitzgerald nods
[13:52] Adelle Fitzgerald: night
http://www.pastebin.ca/1370864
using System;
namespace Generics
{
class Tools
{
internal static T Max<T>(T a, T b) where T : IComparable
{
return a.CompareTo(b)>0 ? a : b;
}
}
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Maximum of {0} and {1} = {2}", 2, 5,
Tools.Max<int>(2,05));
Console.WriteLine("Maximum of {0} and {1} = {2}", 2, 5, Tools.Max
("2","05"));
}
}
}
http://www.pastebin.ca/1370895
public abstract interface IComparable
{
public abstract int CompareTo(object obj);
}
http://www.pastebin.ca/1370896
public interface IComparable
{
public int CompareTo(object obj);
}
http://www.pastebin.ca/1370921
using System;
namespace Generics
{
class Tools<T> where T : IComparable
{
internal static T Max(T a, T b)
{
return a.CompareTo(b)>0 ? a : b;
}
internal static T Min(T a, T b)
{
return a.CompareTo(b)<0 ? a : b;
}
}
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Maximum of {0} and {1} = {2}", 2, 5,
Tools<int>.Max(2,05));
Console.WriteLine("Maximum of {0} and {1} = {2}", 2, 5,
Tools<string>.Max("2","05"));
}
}
}