了解.Net泛型-银行域

本文关键字:Net 泛型 了解 | 更新日期: 2023-09-27 18:25:44

这是一次学习泛型(使用.Net 4.0)的尝试。我已经编程大约4.5年了。到目前为止,我还没有在实时项目中使用泛型。我一直在读一些关于泛型的文章,并试图理解它。问题是,大多数文章都试图解释泛型的各种语法。他们用正方形、圆形和形状等例子进行解释。

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

我现在想到的是一个来自银行领域的例子,目的是理解泛型。我正在努力理解下面的4。

1) 通用类

2) 通用方法

3) 通用接口

4) 普通代理人

EDIT:独立于类型的操作是泛型的好候选者。这是我在下面的例子中遗漏的最大的一点。

我为"泛型类"创建了一个示例。你能为银行域的其他三项提供简单的例子吗?

注意:在使用Generic类时,我发现它对Open-Closed Principle有帮助。即使我添加了新的帐户类型,泛型类也需要更改。变化的逻辑(利息计算)进入特定的类。

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

编辑:根据"BankAccount"类的角色,"AccountManager"会是一个更好的名称吗?这有什么反模式吗?

通用类-银行域示例

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. 什么时候使用泛型与继承比较合适?

  2. 泛型与继承(当不涉及集合类时)

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

  4. 满足开放/封闭原则的工厂模式?

  5. I';我在C#中的泛型和铸造方面遇到了一些问题

  6. 决定何时何地使用泛型http://en.csharp-online.net/CSharp_Generics_Recipes--决定何时何地_使用_通用_问题

  7. 通过泛型与多态的代码重用

  8. 平行遗传链中的多态性和类型安全性

  9. 使用C#泛型进行扩展?

  10. C#泛型和多态性:一种矛盾修饰法?

了解.Net泛型-银行域

仅仅因为"我想使用泛型"就强行将泛型引入项目通常是个坏主意。为正确的工作使用正确的工具。现在,学习新东西的道具。

上面写着。。。基本上,"泛型"是一种在编写时指定方法、类等而不指定底层类型的方法。这是将算法与数据类型分离的好方法。

以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类型的方法

只有我的两美分,因为@Lijo要求我在这里发表评论。

我同意上面的大部分答案。但总的来说,泛型是行为的无类型重用。您的泛型类型必须是IBankAccount(这是一个非常特定的接口),这表明这可能是不对的。我并不是说你不能对接口使用限制,但该接口本身就是一个非常通用的接口,比如IDisposableIConvertible

泛型是关于泛型类型参数的。如果你想对某个东西进行编程,但事先不知道它将应用于哪种类型,那么你可以声明一个泛型类型参数。
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!

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)通用接口:假设您想要完全解耦所有组件(例如,实现控制反转);在这种情况下,如果有像MetricCalculator这样的泛型类在程序集之间使用,则需要通过泛型接口使用它们。另一个例子是,如果您需要编写一个自定义数据结构或迭代器,但我怀疑您是否必须这样做。

4)一般事件:回到MetricCalculator示例,假设您想用一个通知计算完成的事件通知某个观察者对象,并传递结果。这就像一个普通的事件,但在引发事件时会传递一个类型为T的参数注意:如果可用的话,最好使用C#5的异步等待功能。