2

This is an attempt to learn Generics (with .Net 4.0). I have been programming for about 4.5 years. Till now I have not used Generics in real time projects. All the time what I have been doing is reading some article about generics and try to understand it. The problem is – most of them try to explains various syntax available with Generics. They explain with examples such as Square, Circle and shapes.

Now I have got a chance to design a small application. I would like to use Generics there. [I do see good chances of Generics being a good candidate in my new project]

What I have come up with now is an example from Bank domain with the intention of understanding Generics. I am trying to understand the following 4.

1) Generic classes

2) Generic Methods

3) Generic Interfaces

4) Generic Delegates

EDIT: Operations that are type-independant are good candidates for generics. This is the one of the biggest points I missed in my following example.

I have created an example for “Generic classes”. Could you please help with simple examples for other three items with the Bank domain?

Note: While using Generic class, I came to know that it helped in Open-Closed Principle. Even if I add new account type, the generic class need to change. The changing logic (interest calculation) goes inside the specific class.

Note: In the following, the syntax may not be correct as it typed it without a Visual Studio. But the concept holds good.

EDIT: Will "AccountManager" be a more better name for "BankAccount" class based on its role? Is it any kind of anti-pattern?

Generic Class - Example with Bank Domain

Public Interface IBankAccount
{
Public int Interest;
Public Int DepositedAmount;
     Public int DurationInMonth;
}

Public class FixedAccount: IbankAccount
{
Public int Interest 
   {
    Get
    {
   Return  (DurationInMonth*0.5)
    }
    }

Public Int DepositedAmount  {get;set};
    Public int DurationInMonth {get;set};
 }

 Public class SavingsAccount: IbankAccount
{
Public int Interest 
   {
    Get
    {
 Return  ((DurationInMonth/2)*0.1)
    }
   }

Public Int DepositedAmount  {get;set};
    Public int DurationInMonth {get;set};
  }


Public  Class BankAccount<T> Where T: IbankAccount
{
T  account = new T();

Public void CreateAccount(int duration, int amount)
   {
account. DurationInMonth = duration;
account. DepositedAmount   = amont;
int interestVal = account. Interest;
SaveToDatabase (T);

  }

 }

READING:

  1. When is it Appropriate to use Generics Versus Inheritance?

  2. Generics vs inheritance (when no collection classes are involved)

  3. https://codereview.stackexchange.com/questions/8797/how-to-make-sure-that-this-code-conforms-to-open-close-principle

  4. A Factory Pattern that will satisfy the Open/Closed Principle?

  5. I'm having some trouble with generics and casting in C#

  6. Deciding When and Where to Use Generics http://en.csharp-online.net/CSharp_Generics_Recipes—Deciding_When_and_Where_to_Use_Generics_Problem

  7. Code reuse through generics vs polymorphism

  8. Polymorphism AND type safety in parallel inheritance chains

  9. Extending using C# generics?

  10. C# Generics and polymorphism: an oxymoron?

Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418
  • 3
    "Now I have got a chance to design a small application. I would like to use Generics there." - this is not a reason to choose a technology. – Davin Tryon Feb 25 '12 at 20:44
  • 1
    @dtryon - Instead of just advising what is wrong, please back up your arguments and maybe actually help somebody. That is the purpose of this site. – Darren Young Feb 25 '12 at 20:46
  • @dtryon. I don't have any objection with your comment. But I do see good chances of Generics being a good candidate in my new project. – LCJ Feb 25 '12 at 20:47
  • 3
    It would help if you made your code valid to start with: C# is case sensitive. I would concentrate on getting working code before trying to crowbar generics in there. And I really can't see any reason to use generics in what you've written so far, to be honest. – Jon Skeet Feb 25 '12 at 20:50
  • @Jon. Happy to see comment from a person like you. I won't have Visual Studio till Monday to edit it in C#. Apologies for that. I posted it with pseudo code out of my enthusiasm. As I said in post above,the CreateAccount method is Generic. But the details of interest rate calculation varies with specific classes. The SaveToDatabase can be little more verbsoe. Doesn't it become OCP along with the advantage of compile-time type safety? What will be a beter approach? – LCJ Feb 25 '12 at 20:56
  • 2
    @Lijo to echo some other comments here, you shouldn't really try to use generics (or any technique) upfront. Just start writing code you know. If you hit a situation where you're thinking "damn, this is going to get complicated" there's probably a good approach that you don't know how to use yet. And if it's a problem related to not knowing the concrete type of an object at compile-time, generics might be a good solution. There's nothing here that screams "use generics!". Not yet, anyway. – Rex M Feb 25 '12 at 21:12
  • @DarrenYoung didn't mean to offend, I was trying to help by pointing out that OP should make choices based on the requirements of the application. But perhaps I was a bit hasty. – Davin Tryon Feb 25 '12 at 21:37
  • @dtryon I understood what you meant, but probably somebody inexperienced would not. I feel it better to explicitly state your reasoning. I hope I didn't offend in my comment. – Darren Young Feb 25 '12 at 21:57
  • 1
    @Lijo: Actually, CreateAccount isn't generic - BankAccount is, but there's no obvious reason why it *should* be. It's not obvious why it's called BankAccount, to be honest - that doesn't really seem to be its role. Think carefully about what single responsibility each of your classes holds, and the name for that responsibility. – Jon Skeet Feb 25 '12 at 23:52
  • @Jon and all: What I understand from your comment is - what I have done in the name of "BankAccount" class is correct; but the name of the class should be made appropriate based on it's role. Is my understanding correct? What could be the name of the generic class? – LCJ Feb 26 '12 at 04:14
  • 1
    @Lijo: I don't know, because you've only explained one method which already doesn't seem necessarily correct. (What happens if you call CreateAccount more than once? It isn't going to create a second account...) It's also still not clear that it needs to be generic. Why isn't that a method in an abstract base class, for example? – Jon Skeet Feb 26 '12 at 07:33

4 Answers4

3

Shoe-horning generics into a project just because "I want to use generics" is usually a bad idea. use the right tool for the right job. now, props for trying to learn something new.

that said... Basically, a "generic" is a way of specifying a method, class (etc) without specifying an underlying type when you write it. It is a good way to separate your algorithm from you data type.

take, for example, a Swap method. Basically, the swap algorithm is the same no matter what the type it is operating on. So, this would be a good candidate for a generic (as would a List, a Dictionary, etc)

so, a swap for an int would like like this:

void Swap(ref int left, ref int right)
{
   int temp = left;
   left = right;
   right = temp;
}

now, you COULD write overloads for your other datatypes (float, double, etc) or you COULD make it a generic and write it once so it will work on pretty much all datatypes:

void Swap<_type>(ref _type left, ref _type right)
{
   _type temp = left;
   left = right;
   right = temp;
}

now, your sample code wont work:

Public void CreateAccount(int duration, int amount)
{
   T.DurationInMonth = duration;
   T.DepositedAmount   = amont;
   int interestVal = T.Interest;
   SaveToDatabase (T);
}

here, T is the type, not an instance of an object. if you substitute for T, it becomes clearer what is going on:

Public void CreateAccount(int duration, int amount)
{
   IbankAccount.DurationInMonth = duration;
   IbankAccount.DepositedAmount   = amont;
   int interestVal = IbankAccount.Interest;
   SaveToDatabase (IbankAccount);
}

when what you REALLY want is this:

Public void CreateAccount(int duration, int amount)
{
   account.DurationInMonth = duration;
   account.DepositedAmount   = amont;
   int interestVal = account.Interest;
   SaveToDatabase (account);
}

you see, here we are calling the methods of the INSTANCE of the class account, not of the generic IbankAccount TYPE

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
Muad'Dib
  • 28,542
  • 5
  • 55
  • 68
  • Thanks. The use of "type" instead of instance was a typo from my side. I already meant what you have said. Do you have inputs regarding other parts of the question? – LCJ Feb 25 '12 at 21:04
1

0) Using .NET's generic collections with your types as container types: Suppose you want to list all the accounts associated with a specific customer, and display them in a data grid. A List<IBankAccount> would be helpful, or a Dictionary<ICustomerID,IBankAccount> if you wanted to look at more than one customer's account.

1,2) Creating your own generic class and generic methods: Say you want to perform a calculation which involves all accounts in order to generate a report. In this particular report, numerical precision is not important, and speed is. So you could use Single insted of Decimal. In this particular case, to make the classes involved in the calculation independent of the numeric type used, using a generic argument is more natural than inheritance. Pseudo code:

public class MetricCalculator<T>{
    private bool  _dirty;
    private T _cachedValue;

    T PerformCalculation(){
        if( !_dirty )
            return cachedValue;
        T metric = 0;
        foreach( IBankAccount account in AccountMapper.GetAll() ){
            T += account.Foo * accound.Bar;
        }
        _cachedValue = metric;
        return metric;
    }
}

In this example, MetricCalculator is a generic class because one of its data members is of the parameterized type. That member is used to avoid repeating the calculation if the values used haven't changed. There is also a generic method, which performs calculations without caring about the numeric type used. If there were no need to cache the value, you could have just a common class with a generic method. I combined both just to save space.

3) Generic interface: Suppose you want to completely decouple all your components (to implement Inversion of Control, for example) ; in that case, if you had generic classes like MetricCalculator that were used across assemblies, you'd need to use them via a generic interface. Another example would be if you needed to write a custom data structure or iterator, but I doubt you'd have to come to that.

4) Generic events: Back to the MetricCalculator example, suppose that you want to notify some observer object with an event that notifies that the calculation is done, and pass the result. It would be like an usual event, but you'd pass an argument of type T when raising the event. Note: it might be better to use C#5's async-await feature if available.

Community
  • 1
  • 1
dario_ramos
  • 7,118
  • 9
  • 61
  • 108
  • Thanks. #1 is clear. But it does not belong to any of the 4 items I listed in the post, right? Regarding #2. Can you please explain #2 with some pseudo code and tell me in which item (out of 4) it belongs to? – LCJ Feb 25 '12 at 21:00
  • There. I'll think of examples for the other cases and add them soon. – dario_ramos Feb 25 '12 at 21:10
  • I added examples for the other cases. For starters, I recommend you just stick to generic classes and methods, maybe generic events if necessary. I doubt you'll need to write a generic interface. Like other people said, don't try to use generics everywhere; only where they are the most appropiate solution. The other answers should help you build criteria to decide that. – dario_ramos Feb 25 '12 at 21:25
1

Generics are about generic type parameters. If you want to program something and you do not know for which type it will be applied in advance, you would declare a generic type parameter.

class MyStore<T>
{
}

Here T is a generic type parameter. You do not know for which type it stands for.

You could write something like this

class MyStore<T>
{
    public void Store(T item)
    {
        ...
    }

    public T Retrieve()
    {
        ...
    }
}

Now you can use MyStore like this:

var stringStore = new MyStore<string>();
stringStore.Store("Hello");
string s = stringStore.Retrieve();

var intStore = new MyStore<int>();
intStore.Store(77);
int i = intStore.Retrieve();

You could also declare the store like this; however, it would not be type safe

class MyStore
{
    public void Store(object item)
    {
        ...
    }

    public object Retrieve()
    {
        ...
    }
}

You would have to cast the results

var stringStore = new MyStore();
stringStore.Store("Hello");
string s = (string)stringStore.Retrieve();

var intStore = new MyStore();
intStore.Store(77);
int i = (int)intStore.Retrieve();

var doubleStore = new MyStore();
doubleStore.Store("double");
double d = (double)doubleStore.Retrieve(); // OOPS! A runtime error is generated here!
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
1

Just my two cents, since @Lijo asked me to comment here.

I would go with most of the above answers. But to summarise, Generics is typeless reuse of behaviour. The fact that your generic type has to be an IBankAccount -which is a very specific interface - is saying this probably is not right. I am not saying that you cannot use restrictions for an interface but that interface would be a very generic interface itself such as IDisposable or IConvertible.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • Thanks. Operations that are type-independant are good candidates for generics. This is the one of the biggest points I missed in my example. – LCJ Feb 26 '12 at 22:54