泛型接口、方法、委托

 泛型接口:


使用泛型可以定义接口,接口中的方法可以带泛型参数。在链表示例中,就执行了IEnumerable<T>接口,它定义了GetEnumerator()方法,以返回IEnumerator<T>。对于.NET 1.0中的许多非泛型接口,.NET 2.0定义了新的泛型版本,例如IComparable<T>:
public interface IComparable<T>
{
int CompareTo(T other);
}
非泛型接口IComparable需要一个对象,Person类的CompareTo()方法才能按姓氏给人员排序:
public class Person : IComparable
{
public int CompareTo(object obj)
{
Person other = obj as Person;
return this.lastname.CompareTo(other.lastname);

//...
执行泛型版本时,不再需要将object的类型强制转换为Person:
public class Person : IComparable<Person>
{
public int CompareTo(Person other)

return this.lastname.CompareTo(other.lastname);
}
//...
泛型方法:


除了定义泛型类之外,还可以定义泛型方法。在泛型方法中,泛型类型用方法声明来定义。
Swap<T>方法把T定义为泛型类型,用于两个参数和一个变量temp:
void Swap<T>(ref T x, ref T y)
{
   T temp;
   temp = x;
   x = y;
   y = temp;
}
把泛型类型赋予方法调用,就可以调用泛型方法:
int i = 4;
int j = 5;
Swap<int>(ref i, ref j);
但是,因为C#编译器会通过调用Swap方法来获取参数的类型,所以不需要把泛型类型赋予方法调用。泛型方法可以像非泛型方法那样调用:
int i = 4;
int j = 5;
Swap(ref i, ref j);
下面的例子使用泛型方法累加集合中的所有元素。为了说明泛型方法的功能,下面的Account类包含name和balance:
   public class Account
   {
      private string name;
      public string Name
      {
         get
         {
            return name;
         }
      }

      private decimal balance;
      public decimal Balance
      {
         get
         {
            return balance;
         }
      }

      public Account(string name, Decimal balance)
      {
         this.name = name;
         this.balance = balance;
      }
   }
应累加结余的所有账目操作都添加到List<Account>类型的账目列表中:
         List<Account> accounts = new List<Account>();
         accounts.Add(new Account("Christian", 1500));
         accounts.Add(new Account("Sharon", 2200));
         accounts.Add(new Account("Katie", 1800));
累加所有Account对象的传统方式是用foreach语句迭代所有的Account对象,如下所示。foreach语句使用IEnumerable接口迭代集合的元素,所以AccumulateSimple()方法的参数是IEnumerable类型。这样,AccumulateSimple()方法就可以用于所有实现IEnumerable接口的集合类。在这个方法的实现代码中,直接访问Account对象的Balance属性:
   public static class Algorithm
   {
      public static decimal AccumulateSimple(IEnumerable e)
      {
         decimal sum = 0;
         foreach (Account a in e)
         {
            sum += a.Balance;
         }
         return sum;
      }
   }
Accumulate()方法的调用方式如下:
      decimal amount = Algorithm.AccumulateSimple(accounts);
第一个实现代码的问题是,它只能用于Account对象。使用泛型方法就可以避免这个问题。
Accumulate()方法的第二个版本接受实现了IAccount接口的任意类型。如前面的泛型类所述,泛型类型可以用where子句来限制。这个子句也可以用于泛型方法。Accumulate()方法的参数改为IEnumerable<T>。IEnumerable<T>是IEnumerable接口的泛型版本,由泛型集合类实现。
      public static decimal Accumulate<TAccount>(IEnumerable<TAccount> coll)
            where TAccount : IAccount
      {
         decimal sum = 0;

         foreach (TAccount a in coll)
         {
            sum += a.Balance;
         }
         return sum;
      }
将Account类型定义为泛型类型参数,就可以调用新的Accumulate()方法:
      decimal amount = Algorithm.Accumulate<Account>(accounts);
因为编译器会从方法的参数类型中自动推断出泛型类型参数,所以以如下方式调用Accumulate()方法是有效的:
      decimal amount = Algorithm.Accumulate(accounts);
泛型类型实现IAccount接口的要求过于严厉。这个要求可以使用泛型委托来改变。


泛型委托:


通过泛型委托,委托的参数可以在以后定义。
.NET 2.0定义了一个泛型委托EventHandler,它的第二个参数是TEventArgs类型,所以不再需要为每个新参数类型定义新委托了。
public sealed delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs
执行委托调用的方法
把Accumulate()方法改为有两个泛型类型。TInput是要累加的对象类型,TSummary是返回类型。Accumulate的第一个参数是IEnumerable<T>接口,这与以前相同。第二个参数需要Action委托引用一个方法,来累加所有的结余。
在实现代码中,现在给每个元素调用Action委托引用的方法,再返回计算的总和:
      public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u);

      public static TSummary Accumulate<TInput, TOutput>(IEnumerable<T> coll,
            Action<TInput, TSummary> action)
      {
         TSummary sum = default(TSummary);

         foreach (TInput input in coll)
         {
            sum = action(input, sum);
         }
         return sum;
      }
Accumulate方法可以通过匿名方法调用,该匿名方法指定,账目的结余应累加到第二个参数中:
      decimal amount = Accumulate<Account, decimal>(
            accounts, delegate(Account a, decimal d) { return a.Balance + d; });
如果Account结余的累加需要进行多次,就可以把该功能放在一个AccountAdder()方法中:
      static decimal AccountAdder(Account a, decimal d)
      {
         return a.Balance + d;
      }
联合使用AccountAdder方法和Accumulate方法:
      decimal amount = Accumulate<Account, decimal>(
            accounts, AccountAdder);
Action委托引用的方法可以实现任何逻辑。例如,可以进行乘法操作,而不是加法操作。
Accumulate()方法和AccumulateIf()方法一起使用,会更灵活。在AccumulateIf()中,使用了另一个Predicate<T>类型的参数。Predicate<T>委托引用的方法会检查某个账目是否应累加进去。在foreach语句中,只有谓词match返回true,才会调用action方法:
      public static TSummary AccumulateIf<TInput, TSummary>(
            IEnumerable<TInput> coll,
            Action<TInput, TSummary> action,
            Predicate<TInput> match)
      {
         TSummary sum = default(TSummary);

         foreach (TInput a in coll)
         {
            if (match(a))
            {
               sum = action(a, sum);
            }
         }

         return sum;
      }
调用AccumulateIf()方法可以实现累加和执行谓词。这里只累加结余大于2000的账目:
         decimal amount = Algorithm.AccumulateIf<Account, decimal>(
            accounts,
            delegate(Account a, decimal d) { return a.Balance + d; },
            delegate(Account a) {return a.Balance > 2000 ? });


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值