Title: Just Plain Generics
1Just PlainGenerics
Presented by Keith Minder Slides by Steve
WilloughbySenior Architects
2What are Generics?
- Definition
- Generics are classes, structures, interfaces, and
methods that have placeholders (type parameters)
for one or more of the types they store or use. - From MSDN Article "Overview of Generics in the
.NET Framework"
3Advantages
- Type safety
- Code reuse without using object datatype
- Errors at Compile Time
- No boxing of value types
- No casting required
- Improved performance in some applications
- Intellisense
- The Syntax is Most Excellent
4Disadvantages
- The Syntax Is Obtuse
- public static t GIntersectionltt, ugt(t Coll1, u
Coll2, string PropertyName) - where t IList, new()
- where u IList, new()
- VB.Net and C use significantly different syntax
- The JIT compiler will create a version of each
generic method or type for each Specialization
5Definitions
- Generic type parameters
- An instance of a Generic Type is a Constructed
Generic Type - All Generic Types are Open Types
- Constructed Type is an Instance of an Open Type
- Generic type argument
- Constraints
- Type Inference
- Arity
6Constraints
- Enforce Type Restrictions
- Intellisense
- Violations occur at compile time
- Note! Constraint Differences dont create
Overloads
7Guidelines for Using Generics
- Use Generic Collections
- Use Type Parameters instead of Object
- Use NullableltTgt for any optional values
- Avoid Overloads where only differences are
parameter types - Use the most general type possible in constraints
- Be careful using in Static members.
- From .Net 2.0 Generics by Todd Golding
8Behavior
- Language Compiler
- CLR Recognizes Generic Tokens
- IL Code is identical regardless of language
- JIT Compiler
- Each Specialization is Created ONLY when needed
- Code created will be shared for later instances
9A Generic Type
From www.ondotnet.com, New Features in VB.Net -
Generics
10Syntax Examples
ListltTgt and DictionaryltTKey, TValuegt
11Generic Collections ListltTgt
- C
- ListltFileInfogt MyFileList new
ListltFileInfogt() - MyFileList.Add(new FileInfo(C\MyFile.exe))
- Console.WriteLine(MyFileList0.DirectoryName) //
No Cast Required - VB
- Dim FileList As New List(Of FileInfo)()
- FileList.Add(New FileInfo("C\Myfile.exe"))
- Console.WriteLine(FileList(0).DirectoryName) No
Cast Required
12DictionaryltTKey, TValuegt
- Dim Dict As New Dictionary(Of String, FileInfo)
- Dim dir As New DirectoryInfo("c\")
- For Each DirFile As FileInfo In
dir.GetFiles() - Dict.Add(DirFile.Name, DirFile)
- Next
- Dim AFile As FileInfo Dict.Item("boot.ini")
No Cast Required - Console.WriteLine("Created 0",
AFile.CreationTime) - For Each kvp As KeyValuePair(Of String,
FileInfo) In Dict - Console.WriteLine("Name 0, Created
1", _ - kvp.Key, kvp.Value.CreationTime)
No Cast Required - Next
- Notes
- Implemented as a Hash Table very fast lookups
- Elements are of type KeyValuePair
13Collections and Generic Replacements
- Non-Generic Similar
Generic Type - ArrayList ListltTgt
- Hashtable DictionaryltTKey,TValuegt
- SortedList SortedListltTKey,TValuegt
- Queue QueueltTgt
- Stack StackltTgt
- IEnumerable IEnumerableltTgt
- ICollection N/A (use IEnumerableltTgt
anything that extends it) - N/A ICollectionltTgt
- IList IListltTgt
- CollectionBase CollectionltTgt
- ReadOnlyCollectionBase ReadOnlyCollectionltTgt
- DictionaryBase N/A (just implement
IDictionaryltTKey,TValuegt - N/A SortedDictionaryltTKey,TVa
luegt - N/A KeyedCollectionltTKey,TIte
mgt - N/A LinkedListltTgt
- From Krzysztof Cwalina's MSDN Blog
14Syntax Examples
Generic Methods
15Example 1 Simple Subroutine
- C
- public void MyMethodltTgt(T arg)
- String arg
- MyMethod(arg)
- VB
- Public Sub MyMethod(Of T)(ByVal arg As T)
-
- End Sub
- Dim arg As String
- MyMethod(arg)
16Example 2 Simple Function
- C
- public T MyMethodltTgt(T arg)
- String arg In
- String Retval MyMethod(arg)
- VB
- Public Function MyMethod(Of T)(ByVal arg As T) as
T -
- End Function
- Dim arg As String Arg Value
- Dim retval As String MyMethod(arg)
17Example 3 No Type Inference
- C
- public T MyMethodltTgt(Int32 arg)
- String Retval MyMethodltStringgt(arg)
- VB
- Public Function MyMethod(Of T)(ByVal arg as
Int32) as T -
- End Function
- Dim arg As Int32 1234
- Dim retval As String MyMethod(Of String)(arg)
18Example 4 Constraints
- C
- public void DoSomethingltTgt(T Param1) where T
ICollectionltstringgt - public void DoSomethingltT, Ugt(T Param1)
- where T ICollectionltstringgt
- where U struct
- VB
- Public Sub DoSomething(Of T as ICollection(Of
String)) (ByVal arg1 _ As T) - Public Sub DoSomething(Of T As ICollection(Of
String), U As _ Structure)(ByVal arg1 As T, ByVal
arg2 As U)
19Syntax Examples
Generic Types
20Overloaded Classes
- These are valid overloads
- class CalcRateltTgt
- class CalcRateltT, Ugt
- class CalcRateltT, U, Vgt
- These are not
- class CalcRateltTgt
- class CalcRateltTgt where T ICollection
21Mixed Bag
- public class TestClassltT, Ugt where T struct
-
- private ListltTgt _TList new ListltTgt()
- private DictionaryltT, Ugt _Dict new
DictionaryltT, Ugt() - public T AddWidget(T Value)
-
- _TList.Add(Value)
- return Value
-
- public int WidgetCount()
-
- return _TList.Count
-
- public void AddGadget(T Key, U Value)
-
- _Dict.Add(Key, Value)
-
22Performance
23Swap
- Generic
- public class GenericTestltTgt
-
- public void Swap(ref T var1, ref T var2)
-
- T hldr var1
- var1 var2
- var2 hldr
-
-
- Non-generic
- public class NonGenericTest
-
- public void Swap(ref object var1, ref object
var2) -
- object hldr var1
- var1 var2
- var2 hldr
24MSIL Code for Swap
Non-Generic More Flexible
Generic More Efficient(?)
- .method public hidebysig instance void Swap(!T
var1,
!T var2) cil managed -
- // Code size 28 (0x1c)
- .maxstack 2
- .locals init (0 !T hldr)
- IL_0000 nop
- IL_0001 ldarg.1
- IL_0002 ldobj !T
- IL_0007 stloc.0
- IL_0008 ldarg.1
- IL_0009 ldarg.2
- IL_000a ldobj !T
- IL_000f stobj !T
- IL_0014 ldarg.2
- IL_0015 ldloc.0
- IL_0016 stobj !T
- IL_001b ret
- // end of method GenericTest1Swap
.method public hidebysig instance void
Swap(object var1, object var2) cil managed
// Code size 12 (0xc) .maxstack 2
.locals init (0 object hldr) IL_0000 nop
IL_0001 ldarg.1 IL_0002 ldind.ref
IL_0003 stloc.0 IL_0004 ldarg.1 IL_0005
ldarg.2 IL_0006 ldind.ref IL_0007
stind.ref IL_0008 ldarg.2 IL_0009
ldloc.0 IL_000a stind.ref IL_000b ret
// end of method NonGenTestSwap
25Test Results
- Generic Swap
- Using Int32 103 ms
- Using String 163 ms
- Object Swap
- Using Int32 163 ms
- Using String 163 ms
26ListltTgt vs ArrayListArrayList
-
- for (int i 0 i lt 1000000 i)
-
- IntArrayList.Add(i)
- j (int)IntArrayListi
-
- IL_007b ldloc.1
- IL_007c ldloc.s i
- IL_007e box mscorlibSystem.Int32
- IL_0083 callvirt instance int32
mscorlibSystem.Collections.ArrayListAdd(object
) - IL_0088 pop
- IL_0089 ldloc.1
- IL_008a ldloc.s i
- IL_008c callvirt instance object
mscorlibSystem.Collections.ArrayListget_Item(i
nt32) - IL_0091 unbox.any mscorlibSystem.Int32
- IL_0096 stloc.s j
27ListltTgt vs ArrayList - 2
- Listltintgt IntList new Listltintgt()
- for (int i 0 i lt 1000000 i)
-
- IntList.Add(i)
- j IntListi
-
- IL_0029 ldloc.0
- IL_002a ldloc.s I
- IL_002c callvirt instance void class
mscorlibSystem.Collections.Generic.List1ltint32gt
Add(!0) - IL_0031 nop
- IL_0032 ldloc.0
- IL_0033 ldloc.s I
- IL_0035 callvirt instance !0 class
mscorlibSystem.Collections.Generic.List1ltint32gt
get_Item(int32) - IL_003a stloc.s j
28The NullableltTgt Datatype
- Allows value types to accept Null (or VB Nothing)
- Included in the System namespace
- Wont accept DBNull!
- IsNull operator in C, ??, can be used to
supply a default value when a variable is null,
but it cannot supply DBNull.Value - SqlParameter p new SqlParameter("_at_Name", j ??
-1) //this works - //These DONT work
- SqlParameter p new SqlParameter("_at_Name", j ??
DBNull.Value) - p.Value j ! null ? j DBNull.Value
- //this works
- if (j ! null) p.Value j
- else p.Value DBNull.Value
- Two declaration syntaxes in C
- int? i 100
- Nullableltintgt i2 101
29Examples
30Non-Generic ExampleShowFeedbackMsg
- public static void ShowFeedbackMsg(object o,
string Msg, System.Drawing.Color clr) -
- Type t o.GetType()
- PropertyInfo pi t.GetProperty("Text")
- if (pi null)
- throw new Exception(Invalid Object for
ShowFeedbackMsg()) - pi.SetValue(o, Msg, null)
- //Set the forecolor
- pi t.GetProperty("ForeColor")
- if (pi ! null)
- pi.SetValue(o, clr, null)
-
31Generic ExampleShowUserFeedback
- Public Shared Sub ShowUserFeedback(Of T As
ITextControl, WebControl)( _ - ByVal FeedbackText As String, ByVal
ForeColor As System.Drawing.Color, _ - ByVal DisplayControl As T, Optional ByVal
FontBold As Boolean False) - With DisplayControl
- .Text FeedbackText
- .ForeColor ForeColor
- .Font.Bold FontBold
- End With
- End Sub
32Generic Base ClassTypes Set By the Subclass At
Design Time
- public abstract class SWCollectionBaseltTgt
ListltTgt where TSWObjectBase -
- public abstract SWCollectionBaseltTgt
Filter(string FilterValue)
public abstract class SWObjectBase ICloneable,
IComparable private string _Name
public SWObjectBase(string Name)
this.Name Name public string Name
get return _Name
protected set _Name value
public object Clone() return
this.MemberwiseClone() public int
CompareTo(object other) return
Name.CompareTo(((SWObjectBase)other).Name)
33Deriving From the Base Classes
- public class Database SWObjectBase
-
- private DatabaseTables _DatabaseTables
new DatabaseTables() - public Database(string Name)
base(Name) - public DatabaseTables DatabaseTablesColl
-
- get return _DatabaseTables
- set _DatabaseTables value
-
-
- public class DatabaseTables
SWCollectionBaseltDatabaseTablegt -
- public override SWCollectionBaseltDatabaseT
ablegt Filter(string FilterValue) -
- //Implementation Omitted
-
34Using The Subclasses
- SWCollections.Database db new
Database("BigDB") - db.DatabaseTablesColl.Add(new
DatabaseTable("BigTable")) - db.DatabaseTablesColl.Add(new
DatabaseTable("LittleTable")) - db.DatabaseTablesColl.Add(new
DatabaseTable("ShyTable")) - db.DatabaseTablesColl.Add(new
DatabaseTable("FancyTable")) - foreach (DatabaseTable dt in
db.DatabaseTablesColl) -
- Console.WriteLine("\t"
dt.Name) //No Cast -
- db.DatabaseTablesColl.Sort()
- foreach (DatabaseTable dt in
db.DatabaseTablesColl) -
- Console.WriteLine("\t"
dt.Name) //No Cast -
35Generic Base ClassTypes Set At Runtime
- abstract class BaseThingsltT, Ugt where T
ICollectionltUgt, new() -
- protected T _ThingHolder new T()
- public abstract void Add(U Item)
- public T ThingCollection
- get return _ThingHolder
-
class ShinyThingsltT, Ugt BaseThingsltT, Ugt
where T ICollectionltUgt, new()
public override void Add(U Item)
_ThingHolder.Add(Item)
ThingsltListltstringgt, stringgt Ts new
ShinyThingsltListltstringgt, stringgt()
Ts.Add("Yo.") Ts.Add("Ho.")
ThingsltLinkedListltintgt, intgt Ts2 new
ShinyThingsltLinkedListltintgt, intgt()
Ts2.Add(1) Ts2.Add(2) ThingsltLinkedListltstrin
ggt, stringgt Ts3 new ShinyThingsltLinkedListltstrin
ggt, stringgt() Ts3.Add("There once was ")
Ts3.Add("a man from Nantucket")
36IntersectionCollections of Objects
- public static ArrayList OIntersection(ICollection
Coll1, ICollection Coll2, string PropertyName) -
- ArrayList ResultColl new
ArrayList() //The collection returned to
the caller - object Value1, Value2 //Values
used to determine object equality - foreach (object obj1 in Coll1)
-
- Value1 obj1.GetType().GetPropert
y(PropertyName).GetValue(obj1, null) - foreach (object obj2 in Coll2)
-
- Value2 obj2.GetType().GetPro
perty(PropertyName).GetValue(obj2, null) - if (Value2.GetType()
typeof(System.String)) Value2
((string)Value2).ToLower() - if (Value1.Equals(Value2))
-
- ResultColl.Add(obj1)
- break
37Generic Function Collection IntersectionSemi-Gen
eric
- public static TColl GIntersectionltTColl, UColl,
TType, UTypegt( - TColl Coll1,
- UColl Coll2, string PropertyName)
- where TColl IListltTTypegt, new()
- where UColl IListltUtypegt
- where TType MyBase
- where UType MyBase
-
- TColl Result new TColl()
//Return collection - object Value1, Value2
- foreach (TType o1 in Coll1)
-
- Value1 o1.GetType().GetProperty(PropertyNa
me).GetValue(o1, null) - if (Value1.GetType()
typeof(System.String)) Value1
((string)Value1).ToLower() - foreach (UType o2 in Coll2)
38References
- Web Links
- Krzysztof Cwalina's MSDN Blog
- MSDN - "Overview of Generics in the .NET
Framework - OnDotNet.com - Generics in .Net 2.0
- MSDN - Generic Types in Visual Basic
- Books
- .Net 2.0 Generics by Todd Goldring (WROX)
- CLR via C by Jeffrey Richter
39Thats It!!
40Generic Multi-field Comparer
- class MultiSort_Genlttgt IComparerlttgt
-
- private string _Fields
- public MultiSort_Gen(string Fields)
- _Fields Fields
- int Compare(t x, t y)
-
- int result 0
- object xVal new object()
- object yVal new object()
- foreach (string FieldName in _Fields)
-
- if (result 0)
-
- xVal x.GetType().GetProperty
(FieldName).GetValue(x, null) - yVal y.GetType().GetProperty
(FieldName).GetValue(y, null)
41Generic vs Non-GenericValueToNumber
- Private Function ValueToNumber(Of T As
ListControl)(ByVal ListObj As T) As Integer - Implementation removed
- End Function
- Private Function ValueToNumber (ByVal ListObj As
ListControl) As Integer - Implementation removed
- End Function