开发者

'Why' and 'Where' Generics is actually used?

I know that generics are used to achieve type safety and i frequently read that they are largely used in custom collections. But why actually do we need to have them generic?

For example,

Why can't I use string[] instead of List<string>?

Let's consider I declare a generic class and it has a generic type parameter X.

T x;

If I provide a method for the class which does

x = x + 1;

What does it mean actually? I don't know what T is actually going to be and I don't know what x = x + 1 going to perform actually.

If I'm not able to do my own manipulations in my method开发者_JS百科s, how the generics are going to help me anyway?

I've already studied lot of bookish answers. It would be much appreciated if any one can provide some clear insights in this.

Regards, NLV


Your question answers itself. Array types are themselves a form of generic typing. Had we put a generic type system in CLR v1.0, I'd be willing to bet that there would be no special array type, there would just be Array<T> along with List<T> and so on. Since the first version of the CLR did not have generic types, we put into it the most important and obvious generic type, the array type. And as a result, there is a whole bunch of special-purpose code in there just to handle arrays, the one generic type the CLR supported in v1.0.

Since arrays are essentially a generic type, your question answers itself: the reason for generic types in general is the same reason that motivates the creation of the array type pattern. That is: an array type amplifies the ability of its underlying type in a specific way.

An int represents a number. An int[] represents a collection of numbers; we have amplified the notion of number to the notion of a collection of numbers. A Customer represents a customer. A Customer[] represents the notion of a collection of customers. We have amplified the notion of customer to the notion of collection of customer. The mapping from type T to type T[] represents the abstract notion of generically amplifying an instance of a type to a collection of instances of the type.

That same justification motivates all generic types. The Nullable<T> type amplifies a type to the notion of "this thing might be an instance of the type". The IComparable<T> type amplifies a type to the notion of "an instance of this type can be ordered with respect to another instance". And so on. Each generic type is just like the array pattern: it represents the amplification of a type into a new type which provides new operations on that type.

In short: the purpose of the generic type system is to enable you to invent your own type amplifications, and manipulate those amplifications using the type system.


We use generics when we need "higher-order" polymorphism, akin to compile-time duck typing. When we say Foo<T> we mean that Foo<> depends on some property that any possible T can have, and either the given T has this property, or the code fails to compile.

When we say x = x + 1, we imply that T is capable of having 1 added to it, and that the return type is T.


But why actually do we need to have it generic?

If you like, you can also make lots of custom classes: StringList, IntList, DoubleList, etc.. But the point of generics is that you can define your class once and it works for all objects.

And x = x + 1 where x is of the generic type T requires the actual real type to either suppor the addition with int naturally, or have the operator + overloaded with int as the second type.


Actually, I am working on a website atm where generics are making my job a lot easier. I have need to access a lot of information from a database as the entire site is database driven, so I really wanted to have a single class to implement the database functionality. This class is inherited by more classes that know how to deal with their own respective data.

For example, I have a Products class which deals with Products data and a Themes class which deals with themes, etc.,. Well, all of these classes needed a common format for reading and writing to. So, I created a record class which handles this.

Now, here's where the Generics fun begins. I created a Product class, Theme class, etc.,. with strongly typed members such as Name, Manufacturer, ThemeId, however the Records class has no idea how to deal with them. So, the Database class is instanced with a type that relates to the particular class, Product, Theme, etc.,. and the Record class also uses a Generic type, so I can write code such as...

Product.Name = "Cool Product";

then store it like...

Products.InsertRecord(Product coolProduct);

Not only does it save a lot of typing, but it enables me to have a single class that handles all the dirty work, while these small "stub" classes provide me a readable strongly typed interface into it.

Anyways, sorry for the long winded post. Hope this helps you understand the power of generics in at least this instance.


For your first question, you could choose List<string> over string[] if you wanted to dynamically add strings to the list - an array is a fixed size.


Because while string[] is supported (i.e. a custom array type deducted), an array has: * Less functionaltiy than a List or even an IList * is an array, so this does not work for other types of collections. What about dictionaries?

If i'm not able to do my own manipulations in my methods how the generics are going to be help me anyway?

This is a little like asking "if I run a vegetarian restaurant, what good is it I can buy steaks at my supplier?".

Basically, when your projects get more complicated, you WILL write your own manipulations in the methods. You WILL doo all the stuff where it makes sense.


public foobar<T>{
    public Action<string,T> SomeAction;
    public string SomeString;
    public foobar(Action<string,T> s,string m){
         SomeAction=s;
         SomeString=m;
    }


    public void Run(T foo){
         SomeAction(SomeString,foo);
    }
}

Without generics you would have to write a different class for every possiblity, or some other elaborate doings to get the desired results. Generics makes things a bit more elegant.


string[] gives us an array of fixed size. To have a list of dynamic size, we need a class. So if we wanted a list of strings, we might have to create a class called StringList. For doubles, DoubleList. And so on. But what about these classes is unique to those types? Nothing. So instead we create a generic class, List<>, that can accept any type. Instead of having to recreate the same class for different types over and over, generics save us some work.

As for the x = x + 1 problem, you have to expect that T has a + operator that accepts an int on the right side. If it doesn't, it will throw a runtime error. If it does, then that code will assign x to the output of the +operator with x and 1 as arguments.

There are lots of other cases where there are no unique operations performed, and the class/method has to work with more than one type. These are also cases where generics are important and useful.

It's really up to you to decide when and where to use them in your code. If you encounter a problem where they are the best answer, great. Use them. Otherwise, don't. Just don't disqualify them as a solution because they've never been the answer to your specific problem.


A good example from my own work experience has been with managing Linq-To-SQL types. One basic operation that I have to do when creating a new database object is:

  1. Check to see if a requested object exists in the local cache.
  2. Else, Check to see if the requested object exists in the database.
  3. Else, instantiate a new object with the provided parameters.

In this particular project there are around 100 different object types, so writing this code out for each would be cumbersome at best, even with a script, and then what do we do if we have to change something about the method?

Using generics along with constraints, I can do something like this:

public class SQLObjectManager<TEntity> where TEntity : class, new()
{
    public TEntity GetObject(int year, int stateID)
    {
        if( /* entity found in cache */)
            return GetFromCache(year,stateID);
        if( /* entity found in db */)
            return GetFromDB(year,stateID);
        TEntity entity = new TEntity();
        entity.Year = year;
        entity.StateID = stateID;
        return entity;
    }
}

In addition to the benefit of compile-time type checking, I now have a single function to implement and maintain instead of a new version for every table in my database.


Note that if you come from the C++ background, then C# generics and C++ templates are similar concepts. Though, I believe they actually work differently.

Generics exist to write code that is reusable across different types. Generics, increases type safety, reduces casting and boxing.

Suppose you need a stack of integers; a solution would be to come up with an integer stack class. Then for every required datatype(float, string, etc) you would write separate versions of the class; here you would realize that this would tend to code duplication.

Another solution would be to write a stack that is generalized by using object as the element type:

How about following?

MyGenericStack<string> stringStack = new MyGenericStack<string>();
stringStack.Push("One");
stringStack.Push("Two");
stringStack.Push("Three");

MyGenericStack<int> intStack = new MyGenericStack<int>();
intStack.Push(1);
intStack.Push(2);
intStack.Push(3);

MyGenericStack<CustomObject> customObjectStack = new MyGenericStack<CustomObject>();
customObjectStack.Push(new CustomObject(1));
customObjectStack.Push(new CustomObject(2));
customObjectStack.Push(new CustomObject(3));

Following is the generic class

public class MyGenericStack<T>
{
    int position;
    T[] data = new T[10];
    public void Push(T obj) { data[position++] = obj; }
    public T Pop() { return data[--position]; }

    public void Show()
    {

        for (int i = 0; i < data.Length; i++)
        {
            //Console.WriteLine("Item: {0}", data[i]);
            //MessageBox.Show(String.Format("Item: {0}", data[i]));
        }
    }
}

Yes I know, now you'd too fall in love with Generics!

Btw, if you ever plan to compare inheritance and generics then keep in mind that inheritance has the reuseability with a base type, while generics expresses reuseability with a template type.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜