블로그 이미지
Sunny's

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

'IComparable'에 해당되는 글 1

  1. 2009.04.28 Generics: Constraints, IComparable, and IEnumerable
2009. 4. 28. 08:53 .NET Framework
Pharmacy customer: "Don't you have the Generic version of this?"
Pharmacist:               "Sorry,Sir. We're still on Framework 1.1"

In working with Generic classes, particularly collections, you will soon encounter situations where you will want to restrict the possible types that the generic class will accept. You may need to ensure that your collection only accepts reference types, not value types. Or, you may need to make sure that the object derives from another class or implements a particular interface such as IComparable<T>. To do this, you would use what is called a Constraint.

The example presented here makes use of a CustomUserList Collection class that will only accept types that are reference types (a class, not a struct), and that implement IComparable<T> and IEnumerable<T>. I will present both the collection class, the object type that it can hold, and provide a Windows Forms test harness that will allow you to add test items and will show you the list.

Here is the signature of the class:

public class CustomUserList<T> where T: class, IComparable<T>, IEnumerable<T>
{ ...

When you code Constraints, they must be coded in a specific order. If you want to constrain your generic type to a class or structure, you code the class or struct keyword first. If you want to constrain the generic type to a derived class of a particular class, you must code the name of that class first, and not use the "class" or "struct" keywords. Following the above, you can code a list of the interfaces that the type must implement. Lastly, if you need to constrain the generic type to a class that has a default constructor, you can add the new() keyword at the end of the list.

Implementing IComparable and IEnumerable

Below I present the User class, which specifically implements IComparable<User> and IEnumerable<User>

using System;

using System.Collections.Generic;

using System.Text;

 

namespace CustomList

{

  public   class User : IComparable<User>, IEnumerable<User>

    {

      public int UserId;

      public string FirstName;

      public string LastName;

      public string Email;

 

 

      public User(int userId, string firstName, string lastName, string email)

      {

          this.UserId = userId;

          this.FirstName = firstName;

          this.LastName = lastName;

          this.Email = email;

      }

 

      public int CompareTo(User otherUser)

      {

          return this.LastName.CompareTo(otherUser.LastName);

      }

 

      public bool Equals(User u)

      {

          return (this.LastName  == u.LastName);

      }

 

 

      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

      {

          yield return this;

      }

 

      IEnumerator<CustomList.User> IEnumerable<CustomList.User>.GetEnumerator()

      {

          yield return this;

 

      }

  }  

}


IComparable has only one member, the CompareTo method. In this case we want a list that sorts automatically by LastName, so I've implemented compareTo to return the results of a string comparison on it.

The implementations of the non-generic GetEnumerator and the Generic IEnumerable<T>.GetEnumerator methods are boilerplate. There is nothing special to do here, but they must be implemented. So we simply use the yield return construct to return a reference to the current instance.

Now let's look at the code for the CustomUserList Class:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace CustomListLib

{

    public class  CustomUserList<T> where T: class,IComparable<T>, IEnumerable<T>

    {

        private List<T> list = new List<T>();

 

        public IEnumerator<T> GetEnumerator()

        {

            foreach (T item in list)

            {

                yield return item;

            }

        }

 

        public void Add(T item)

        {

            if (list.Count == 0)

            {

                list.Add(item);

            }

            else

            {

                for (int i = 0; i < list.Count; i++)

                {

                    T currentItem = list[i];

                    T nextItem = null;

                    if (i < list.Count - 1)

                    {

                        nextItem = list[i + 1];

                    }

                    int currentComparer = currentItem.CompareTo(item);

                    if (nextItem == null)

                    {

                        if (currentComparer >= 0)

                        {

                            list.Insert(i, item);

                            break;

                        }

                        else if (currentComparer < 0)

                        {

                            list.Add(item);

                            break;

                        }

                    }

                }

            }

        }

    }

}


The GetEnumerator method, again, employs the handy yield return construct, and the Add method is where I put in the use of the IComparable interface to enforce "automatic alphabetical sorting" on my list. If you fire up the Windows Forms Test harness and start adding users, you will see that the ListView at the bottom of the form automatically displays the contents in Last Name order. Strange bedfellows - you don't have to go to Arizona to find Yuma.

 


Download the Visual Studio 2005 Solution that accompanies this article


CompTIA Certification Pak
Customize your own CompTIA Pak to fit your needs. Select any four of Transcender's CompTIA-related products.


출처 : http://www.eggheadcafe.com/tutorials/aspnet/7c431a9f-8cbd-4f5c-8397-9c412a25b257/generics-constraints-ic.aspx
posted by Sunny's
prev 1 next