了解.Net Generics - Bank Domain

时间:2012-02-25 20:39:32

标签: c# .net vb.net generics

这是尝试学习泛型(使用.Net 4.0)。我已经编程了大约4。5年。直到现在我还没有在实时项目中使用泛型。我一直在做的是阅读一些关于泛型的文章并尝试理解它。问题是 - 他们中的大多数试图解释泛型的各种语法。他们用例如方形,圆形和形状的例子来解释。

现在我有机会设计一个小应用程序。我想在那里使用泛型。 [我确实看到Generics在我的新项目中成为一个好候选人的机会很大]

我现在想出的是来自Bank域的一个例子,旨在理解泛型。我想了解以下4个。

1)通用类

2)通用方法

3)通用接口

4)通用代表

编辑:独立类型的操作是泛型的良好候选者。这是我在以下示例中遗漏的最重要的一点。

我为“通用类”创建了一个示例。你能帮忙用银行域名帮助其他三个项目的简单例子吗?

注意:在使用Generic类时,我发现它在开放 - 封闭原则中有所帮助。即使我添加新的帐户类型,通用类也需要更改。变化的逻辑(利息计算)进入特定的类。

注意:在下文中,语法可能不正确,因为它在没有Visual Studio的情况下键入它。但这个概念很有用。

编辑: Will" AccountManager"是" BankAccount"更好的名字基于它的角色?这是什么样的反模式?

通用类 - 银行域示例

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);

  }

 }

读:

  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. 决定何时何地使用泛型 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?

4 个答案:

答案 0 :(得分:3)

仅仅因为“我想使用仿制药”而成为一个项目的鞋子通常是一个坏主意。使用合适的工具来做正确的工作。现在,尝试学习新东西的道具。

说... 基本上,“泛型”是一种在编写方法时指定方法,类(等)而不指定基础类型的方法。这是将算法与数据类型分开的好方法。

例如,采用Swap方法。基本上,无论操作类型如何,交换算法都是相同的。所以,这将是通用的一个很好的候选者(如ListDictionary等等。

所以,int的交换是这样的:

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

现在,您可以为其他数据类型(floatdouble等编写重载 或者你可以使它成为通用的并写一次,这样它几乎适用于所有数据类型:

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

现在,您的示例代码无效:

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

这里,T是类型,而不是对象的实例。如果你替换T,它会变得更清楚:

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

当你真正想要的是这个:

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

你知道,我们在这里调用类帐户的INSTANCE方法,而不是通用的IbankAccount TYPE

答案 1 :(得分:1)

0)将.NET的通用集合与您的类型用作容器类型:假设您要列出与特定客户关联的所有帐户,并将其显示在数据网格中。如果您想要查看多个客户的帐户,List<IBankAccount>会有所帮助,或Dictionary<ICustomerID,IBankAccount>

1,2)创建自己的泛型类和泛型方法:假设您要执行涉及所有帐户的计算以生成报告。在这个特定的报告中,数值精度并不重要,速度也是如此。因此,您可以Single使用Decimal。在这种特殊情况下,为了使计算中涉及的类独立于所使用的数字类型,使用泛型参数比继承更自然。伪代码:

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;
    }
}

在此示例中,MetricCalculator是一个泛型类,因为其中一个数据成员属于参数化类型。如果使用的值未更改,则该成员用于避免重复计算。还有一种通用方法,可以在不关心所使用的数字类型的情况下执行计算。如果不需要缓存该值,则可以只使用泛型方法的公共类。我把两者结合起来只是为了节省空间。

3)通用接口:假设您要完全解耦所有组件(例如,实现Inversion of Control);在这种情况下,如果您使用跨程序集使用的MetricCalculator等泛型类,则需要通过通用接口使用它们。另一个例子是如果你需要编写一个自定义数据结构或迭代器,但我怀疑你不得不这样做。

4)通用事件:返回MetricCalculator示例,假设您要通过一个事件通知某个观察者对象,该事件通知计算已完成,并传递结果。它就像一个常见的事件,但在提升事件时你会传递T类型的参数。 注意:如果可用,最好使用C#5的async-await功能。

答案 2 :(得分:1)

泛型是关于泛型类型参数。如果你想编写一些东西而你不知道它将提前应用哪种类型,你会声明一个泛型类型参数。

class MyStore<T>
{
}

此处T是泛型类型参数。你不知道它代表的是哪种类型。

你可以写这样的东西

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

    public T Retrieve()
    {
        ...
    }
}

现在您可以像这样使用MyStore

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

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

您也可以像这样申报商店;但是,它不是类型安全的

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

    public object Retrieve()
    {
        ...
    }
}

您必须投射结果

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!

答案 3 :(得分:1)

只是我的两分钱,因为@Lijo让我在这里发表评论。

我会选择上述大部分答案。 但总而言之,泛型是无类型重用行为。您的泛型类型必须是IBankAccount - 这是一个非常具体的接口 - 这说明这可能是不对的。我并不是说您不能对接口使用限制,但该接口本身就是一个非常通用的接口,例如IDisposableIConvertible