asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Generics In-Depth - Cont'd
By J. Ambrose Little


  • email this article to a colleague
  • suggest an article

    Constraints

    Now that we've lain the foundation for creating and using generic types, we should consider an extremely important aspect in generic type usage-constraints. Constraints are a feature of .NET generics that enable the creator of a generic to specify that only certain types may be passed in as type arguments to his generic.

    Constraints solve a problem that involves the usage of type parameters within a generic type. Consider the code in Listing 4. Looks good, right? Should run fine, right? Well, as long as the type passed in as T can be instantiated with "new," and as long as T has a method called Contains that accepts a String argument, it will run just fine.

    Listing 4 – No Constraints

    [C#]

          public class MyClass<T, K>

          {

                public void DoSomething()

                {

                      T temp = new T();

                      Debug.Assert(temp.Contains(“test”));

    }

          }

    [VB .NET]

          Public Class MyClass(Of T, K)

                Public Sub DoSomething()

                      Dim temp As T = New T()

                      Debug.Assert(temp.Contains(“test”))

                End Sub

          End Class

    But how can we be sure that the user of MyClass will pass in a type that that supports these operations? That is the problem, and the solution is constraints. In Listing 5, we see the same code, more or less, as in Listing 4, but we have added constraints to ensure that our code will not break at runtime because the compiler will not allow users of MyClass to pass in a type T that does not follow the constraints we have specified.

    The "new" constraint specifies that the type supplied for T must be able to be instantiated using the "new" keyword, which must come last for C#. The other constraint specifies that the type T must implement IList, so it should have a method called Contains that accepts a String parameter. Note that C# lets you specify constraints for each type parameter by using multiple "where" clauses, whereas VB .NET lets you do this by adding "As" after each parameter.

    Listing 5 – With Constraints

    [C#]

          public class MyClass<T,K> where T: IList, new()

                                    where K: IComparable

          {

                public void DoSomething()

                {

                      T temp = new T();

                      Debug.Assert(temp.Contains(“test”));

    }

          }

             

    [VB .NET]

          Public Class MyClass(Of T As {New, IList}, K As IComparable)

                Public Sub DoSomething()

                      Dim temp As T = New T()

                      Debug.Assert(temp.Contains(“test”))

                End Sub

          End Class

    You can specify up to one base class, any number of interfaces, and the "new" constraint as constraints for a generic type or method.

    At this point, you may be wondering about the usage of single, capital letters as identifiers for the type parameters. This is actually a recommendation coming out of Microsoft that will most likely make it into the design guidelines. The reasoning is simply that this convention will make members, parameters, and variables that use the type parameters stand out from those that use "normal" types.

    Generic Methods and Type Inference

    As mentioned earlier, not only can you create generic types, you can also create generic methods, which are simply methods that have type parameters. Generic methods are useful in many situations, particularly where you need the return type to be variable as in, e.g., factory methods. The nifty thing about these is that you can use the type parameter(s) as the return value and normal parameter types as well as within the method for local variables.

    We already saw an example of the syntax in Listing 1, but the example in Listing 5 shows all three ways that generic method type parameters can be used. Note how we are using the type parameter as the return value's type, the type of the "input" parameter, and the type of the local method variable "tempVar."

    Lisitng 6 – Generic Methods

    [C#]

    public T DoSomething<T>(T input, string input2)

    {

          T tempVar;

    }

    [VB .NET]

          Public Function DoSomething(Of T)(ByVal input As T, _

     ByVal input2 As String) As T

                Dim tempVar As T;

          End Function

    Another useful feature of these methods is called "type inference." Simply put, this is the ability of the runtime to infer the type of a type parameter based upon the type of a method argument. For instance, in Listing 6, if we were to pass in an integer to the "input" method parameter, the runtime could infer that the type of the type parameter "T" is Int32, so we would not have to actually specify that when calling the method. This is illustrated in the difference between Listing 7 and Listing 8.

    Listing 7 – Using a Generic Method without Type Inference

    [C#]

          int myInt = DoSomething<int>(55, “Test”);

    [VB .NET]

          Dim myInt As Integer = DoSomething(Of Integer)(55, “Test”)

    In Listing 7, we see that we are explicitly specifying the type parameter as an Int32; however, since the runtime can easily infer this from the type of the argument we're passing for the "input" parameter (i.e., 55), explicitly specifying the type of the type parameter is not necessary, so we can omit it, as we have in Listing 8.

    Listing 8 – Using a Generic Method  with Type Inference

    [C#]

          int myInt = DoSomething(55, “Test”);

    [VB .NET]

          Dim myInt As Integer = DoSomething(55, “Test”)

    Note that there are situations where the runtime cannot infer the type parameter. In cases where there are multiple method parameters using the type parameter as their type and different types are passed as arguments to these parameters (in the same call), the runtime will not be able to infer what the type parameter is. This is demonstrated in Listing 9.

    Listing 9 – Problems with Inference

    [C#]

          // Generic method

          public void DoSomething<T>(T input1, T input2)

          {

                // …

          }

          // Using generic method with type inference

          DoSomething(71, “Farscape”); // Won’t work

          DoSomething<object>(71, “Farscape”); // Works

    [VB .NET]

          ‘// Generic method

          Public Sub DoSomething(Of T)(ByVal input1 As T, _

     ByVal input2 As T)

                ‘// …

          End Sub

          ‘// Using generic method with type inference

          DoSomething(71, “Farscape”) ‘// Won’t work

          DoSomething(Of Object)(71, “Farscape”) ‘// Works

    In the first usage in Listing 9, the runtime cannot infer the type of the type parameter "T" because the types of the arguments passed to the two method parameters using that type parameter are different, i.e., they are Int32 and String. To resolve this confusion, we must explicitly specify the type for the type parameter, as we have done in the second example using System.Object.

    Notes Regarding Generics in .NET

    Generics Code Restrictions
    So now we've covered most of the syntax and terminology relating to generics. We have yet to fully consider the limitations that the CLR's implementation of generics imposes upon us.

    Since generics without constraints are perceived by the compiler to be System.Object types, you cannot access any type members not available to System.Object nor can you use arithmetic operators or nested classes. You can apply constraints to relax these restrictions; however, you still cannot access static members or nested classes without explicitly casting. You also cannot use arithmetic operations unless the base class specified in the constraints list supports them. Finally, you cannot use generics themselves as type arguments, but, as demonstrated, you can use constructed types as type arguments.

    Generics in the CLR (Advanced)
    For those of you who are interested in how the CLR actually handles generics in memory, you should know that it handles value types differently from reference types. One type is created for each unique value-type type argument. That type is then reused for all other constructed types having the same type parameter. This improves performance by not requiring any type casting.

    One type is created for all reference-type type arguments, using object references as the type parameter. That type is reused for all other constructed types that are reference types. This reduces code bloat in memory.

    In both cases, full use of reflection can be used to obtain information about the types at runtime.

    VB .NET
    It's great that the VB .NET team has been working to provide support for generics. I have tried to provide equivalent examples in C# and VB .NET in this article, and for the most part, there is equivalency. However, VB .NET has a few limitations in the PDC version (listed below). I have been told that these will be lifted with the beta releases, and in fact, most appear to be fixed in the current community preview version.

    • Checking on multiple constraints-runtime errors may occur.
    • "New" constraint.
    • Some cases of overload resolution for generic methods won't bind correctly.
    • Overloading on Arity - overloading on the number of type parameters (i.e., allowing Collection(Of T) and Collection(Of K, V) to exist in the same namespace).
    • Generic Delegates.
    • Some collection classes have yet to be included in the System.Collections.Generic namespace.
    • UI features: Intellisense, object browser, pretty listing, and drop downs.

    In the PDC version, the VB .NET documentation refers to generics as "data type arguments." I have suggested to them that they either change this or at least make it list under the "generics" topics in order to help folks find information about it. In the meantime, be aware of the nomenclature difference.

    What About C++ Templates?
    Another common question relates to how generics compare to C++ templates. Both provide parameterized types, but .NET aims at ease of use and consequently sacrifices some flexibility. Below is a short list of features not available in .NET generics that are available in C++ templates.

    • No non-type template parameters, e.g., template <int i> {}.
    • No explicit or partial specialization, i.e., customization of template or subset of arguments for a particular type.
    • Type parameters cannot be used as the base class for a generic type.
    • No default types for type parameters.
    • Generics cannot be used as type parameter, although constructed types can be.

    .NET does offer one big benefit over C++ templates. C++ allows code that may not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. .NET requires code in a class to be written in such a way that it will work with any type that satisfies the constraints. For example, in C++, it is possible to write a function that uses the arithmetic operators + and - on objects of the type parameter, which will produce an error at the time of instantiation of the template with a type that doesn't support these operators. .NET disallows this; the only language constructs allowed are those that can be deduced from the constraints.

    And How Does Java Compare?
    Java will support generics in the next release. The most significant difference between generics in Java and those in .NET is that the JVM will not be modified, so support for value types will be based on down casting from the constraint type or the Object type. The JVM will also generate only one specialized type at compile time to generate all constructed types, and since the JVM will not be modified, runtime detection of the type of type parameters will be impossible.

    Wrapping Things Up

    I am including two download sample applications that make use of generics functionality. The first is pretty much academic in that it is simply an effort to demonstrate some of the generics functionality. In it you can see the use of type parameters to enable the instance of the medieval person to know what type of person he is in the company of. This knowledge then dictates the behavior of the person. You can easily abstract this to any situation where such conditional behavior might be desired.

    I'm also including an object pooler that I wrote to replace the dependency on COM+ for that feature. Since COM+ involves a fair amount of overhead in marshaling data, and since I have seen what appear to be memory leaks in it, I wrote this pooler in v1.1. I quickly was bothered by some of the difficulties regarding type inheritance. Since I wanted to mirror COM+ as much as possible (to minimize impact on our existing application), I wrote it so that my classes could inherit from a base class that hooks into the pooling services, much like the ServicedComponent does for COM+.

    The problems with writing this in v1.1 are that I had to pass around instances of deriving types' System.Type, and on every class that requires the pooling functionality, I had to declare a new factory "Create" method to get the objects from the pool. Rewriting this in v2.0, I was able to eliminate a lot of the System.Type passing, using type parameters and arguments instead, and I was able to eliminate the need to redeclare the factory method on inheriting types.

    The only thing that I'm still not entirely happy with is that you still have to declare the constructor overload that accepts a Boolean, since types do not inherit constructors.

    In any case, I'm not going to go over the code in depth in this article; however, if you are looking for a useful, real-world application of generics beyond the simple collection types in the System.Collections.Generic namespace, you might be interested in checking this application out.

    I hope these last few sections have not left you feeling stunned. If they have, take a break and come back to read just the parts before the "Notes" section. Review the "Problems Solved" section to refresh in your mind some common scenarios where generics apply. Then, when you feel comfortable with the syntax, concepts, and terminology, you may want to revisit some of the more advanced notes and dig into the sample applications.

    Other Resources

    If you still feel like you're not comfortable with generics, here are some other resources that may help you:

    http://weblogs.asp.net - There are a number of bloggers covering this and other v2.0 aspects.
    Generics Design Guidelines
    MSDN Docs that ship with Whidbey
    System.Collections.Generic Namespace
    Intro to Generics - By Rob Chartier
    http://www.google.com - Google is your friend. Just do a search for "generics .net" sans quotes.

    About the Author

    J. Ambrose Little is the editor-in-chief of the ASPAlliance, an ASPInsider, and a Microsoft ASP.NET MVP who currently works for a large credit union in Tampa, FL as their Web Architect. Previously he worked as a consultant at Verizon, creating XML Web Services and middle tier components, and for BOk Financial's Web Services department creating ASP.NET applications for their intranet. His pre-.NET programming experience consists mostly of developing web applications using ASP and VB COM/DCOM for several years.

    He has a BA in Medieval European History, which remains an interest. Apart from developing software, he enjoys movies, reading, writing, apologetics, billiards, foosball, chess, badminton, and spending time with his wife, Christiane, and daughter, Bridget.

    Ambrose can be reached at ambrose@aspalliance.com. << Introduction

    Rate This Article

  • Other Articles
    Feb 23, 2005 - My Feature in Visual Basic 2005
    In this article, Thiru Thangarathinam demonstrates the different classes and features available through the My namespace. By providing a speed-dial that allows you to more quickly and effectively utilize .NET framework functionalities in your application, the My feature provides huge productivity improvements for .NET developers.
    [Read This Article]  [Top]
    Oct 6, 2004 - Creating Triggers Using Managed Code in SQL Server 2005
    Thiru Thangarathinam discusses taking advantage of the integation between the .NET CLR and SQL Server 2005 in order to do things like create triggers using managed code.
    [Read This Article]  [Top]
    Sep 8, 2004 - Custom Object Data Binding with .NET
    Developers often use brute force coding to marshal data between the GUI and application objects. In this article, Luther Stanton explains how to use .NET's out-of-the box data-binding functionality to make this job much easier.
    [Read This Article]  [Top]
    Aug 17, 2004 - The Perfect Service - Part 2
    Ambrose Little provides the complete source code for his 'Perfect Service' and explains how the .NET Service Manager enables features such as drag-n-drop deployment.
    [Read This Article]  [Top]
    Aug 12, 2004 - Middle-Tier Hosting: Enterprise Services, IIS, DCOM, Web Services, and Remoting
    There is broad-reaching debate about remoting, Web services, Enterprise Services, and DCOM. In short, it is a debate about the best technology to use when implementing client/server communication in .NET. Rocky Lhotka shares his thoughts on the issue while offering clear explanations of basic application architecture terminology.
    [Read This Article]  [Top]
    Jul 21, 2004 - COM Interop Exposed
    This article provides and excellent foundation for COM Interop. It reviews COM's background, explains how VB6 interacts with COM, and then shows how to design .NET components to smoothly interact with COM.
    [Read This Article]  [Top]
    Jun 24, 2004 - The Perfect Service - Part 1
    The first article in this two-part series shows how to get Ambrose Little's .NET Service Manager running and then how to add plug-n-play services to it using drag-n-drop or XCOPY.
    [Read This Article]  [Top]
    May 25, 2004 - Generics In-Depth
    Although generics are extremely useful, they also seem to have a certain mystique that cannot be readily explained. This article hopes to remove that aura of mystery by showing just how easy it is to use generics and how useful they can be in many common situations.
    [Read This Article]  [Top]
    May 11, 2004 - SharePoint Security and .NET Impersonation
    When implementing custom components that require access to restricted resources, implicit impersonation must be used. Jay Nathan shows how to create a class that makes using .NET Impersonation a snap.
    [Read This Article]  [Top]
    Mar 23, 2004 - Exploiting .NET's Advanced Deployment Features
    Tony Arslan shows how to use VS .NET's custom deployment feature to create configuration files on the target machine during installation.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info

    Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers