Understanding .Net Generics - Bank Domain

旧街凉风 提交于 2020-01-13 06:13:05

问题


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?


回答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.




回答2:


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




回答3:


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!



回答4:


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.



来源:https://stackoverflow.com/questions/9447865/understanding-net-generics-bank-domain

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!