了解.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);
}
}
阅读:
什么时候使用泛型与继承比较合适?
泛型与继承(当不涉及集合类时)
https://codereview.stackexchange.com/questions/8797/how-to-make-sure-that-this-code-conforms-to-open-close-principle
满足开放/封闭原则的工厂模式?
I';我在C#中的泛型和铸造方面遇到了一些问题
决定何时何地使用泛型http://en.csharp-online.net/CSharp_Generics_Recipes--决定何时何地_使用_通用_问题
通过泛型与多态的代码重用
平行遗传链中的多态性和类型安全性
使用C#泛型进行扩展?
C#泛型和多态性:一种矛盾修饰法?
仅仅因为"我想使用泛型"就强行将泛型引入项目通常是个坏主意。为正确的工作使用正确的工具。现在,学习新东西的道具。
上面写着。。。基本上,"泛型"是一种在编写时指定方法、类等而不指定底层类型的方法。这是将算法与数据类型分离的好方法。
以Swap方法为例。基本上,交换算法是相同的,无论它在什么类型上操作。因此,这将是通用(如List
、Dictionary
等)的一个很好的候选者
因此,int
的交换如下所示:
void Swap(ref int left, ref int right)
{
int temp = left;
left = right;
right = temp;
}
现在,您可以为其他数据类型(float
、double
等)编写重载或者你可以把它做成一个泛型并写一次,这样它几乎可以处理所有的数据类型:
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
(这是一个非常特定的接口),这表明这可能是不对的。我并不是说你不能对接口使用限制,但该接口本身就是一个非常通用的接口,比如IDisposable
或IConvertible
。
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的异步等待功能。