通过昨天的例子可以看到泛型类型实现IAccount接口的要求过于严厉。为了将Accumulate()方法改为泛型方法,还要去创建一个IAccount接口,然后让Account类继承IAccount接口,然后....杯具( ⊙ o ⊙ )啊! 在今天的例子中,我们可以创建独立于任何接口的泛型方法。这个就需要泛型委托机制来帮忙实现了。
下面是修改后的泛型委托的例子
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; namespace GenericMethod { // 定义一个泛型委托 // TInput是要累加的对象 // TSummary是返回类型 public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u); 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; } } public static class Algorithm { // 使用委托的泛型方法 public static TSummary Accumulate<TInput, TSummary>(IEnumerable<TInput> coll, Action<TInput, TSummary> action) { TSummary sum = default(TSummary); foreach (TInput input in coll) { sum = action(input, sum); } return sum; } } class Program { static void Main(string[] args) { List<Account> accounts = new List<Account>(); accounts.Add(new Account("Christian", 1500)); accounts.Add(new Account("Sharon", 2200)); accounts.Add(new Account("Katie", 1800)); // 通过匿名方法调用 //decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, delegate(Account a, decimal d){return a.Balance + d;}); // 还可以通过λ表达式调用 decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, (a, d) => a.Balance + d;); Console.WriteLine(amount.ToString()); Console.ReadLine(); } } }
郁闷了,编译有个错误:
Error 1 ) expected E:\C Sharp\ComputerManager\GenericMethod\GenericMethod\Program.cs 70 102 GenericMethod
Error 2 Invalid expression term ')' E:\C Sharp\ComputerManager\GenericMethod\GenericMethod\Program.cs 70 103 GenericMethod
Error 3 Only assignment, call, increment, decrement, and new object expressions can be used as a statement E:\C Sharp\ComputerManager\GenericMethod\GenericMethod\Program.cs 70 102 GenericMethod
编译怎么出问题了,实在不解,待会儿查下。
NOTE:偶晕倒,原来是这里出问题了
decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, (a, d) => a.Balance + d;);
应该是这样写,多了一个分号囧
decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, (a, d) => a.Balance + d);
通过匿名方法调用的那个是没有任何问题的。
下面的这个就是标准的委托形式了,这个看不懂,就要回去看下委托的章节了。
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; namespace GenericMethod { // 定义一个泛型委托 // TInput是要累加的对象 // TSummary是返回类型 public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u); 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; } } public static class Algorithm { // 使用委托的泛型方法 public static TSummary Accumulate<TInput, TSummary>(IEnumerable<TInput> coll, Action<TInput, TSummary> action) { TSummary sum = default(TSummary); foreach (TInput input in coll) { sum = action(input, sum); } return sum; } public static decimal AccountAdder(Account a, decimal d) { return a.Balance + d; } } class Program { static void Main(string[] args) { List<Account> accounts = new List<Account>(); accounts.Add(new Account("Christian", 1500)); accounts.Add(new Account("Sharon", 2200)); accounts.Add(new Account("Katie", 1800)); // 通过匿名方法调用 //decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, delegate(Account a, decimal d){return a.Balance + d;}); // 还可以通过λ表达式调用 //decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, (a, d) => a.Balance + d;); // 使用标准的委托形式 // 单独再写一个AccountAdder方法 decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, Algorithm.AccountAdder); Console.WriteLine(amount.ToString()); Console.ReadLine(); } } }
这样就很灵活了,你可以在Action方法里面想做什么就做什么,可以乘法除法都可以了。
下面再做一个扩展可以在Accumulate的时候加入一个委托应用来检查某个账目是否应累加进去。
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; namespace GenericMethod { // 定义一个泛型委托 // TInput是要累加的对象 // TSummary是返回类型 public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u); 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; } } public static class Algorithm { // 使用委托的泛型方法 public static TSummary Accumulate<TInput, TSummary>(IEnumerable<TInput> coll, Action<TInput, TSummary> action) { TSummary sum = default(TSummary); foreach (TInput input in coll) { sum = action(input, sum); } return sum; } public static decimal AccountAdder(Account a, decimal d) { return a.Balance + d; } 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; } } class Program { static void Main(string[] args) { List<Account> accounts = new List<Account>(); accounts.Add(new Account("Christian", 1500)); accounts.Add(new Account("Sharon", 2200)); accounts.Add(new Account("Katie", 1800)); // 通过匿名方法调用 //decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, delegate(Account a, decimal d){return a.Balance + d;}); // 还可以通过λ表达式调用 //decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, (a, d) => a.Balance + d); // 使用标准的委托形式 // 单独再写一个AccountAdder方法 // decimal amount = Algorithm.Accumulate<Account, decimal>(accounts, Algorithm.AccountAdder); // 新委托方法的调用 decimal amount = Algorithm.AccumulateIf<Account, decimal>(accounts, (a, d) => a.Balance + d, a => a.Balance > 2000); Console.WriteLine(amount.ToString()); Console.ReadLine(); } } }
对Array类使用泛型方法
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; namespace ArrayGenericDelegate { public class Person { private string firstName; public string FirstName { get { return firstName; } } private string lastName; public string LastName { get { return lastName; } } public Person(string firstname, string lastname) { this.firstName = firstname; this.lastName = lastname; } } public class Racer { public string Name { get; set; } public string Team { get; set; } public Racer(string name) { this.Name = name; } } class Program { static void Main(string[] args) { Person[] persons = { new Person("Emerson", "Fittipaldi"), new Person("Niki", "Lauda"), new Person("Ayrton", "Senda"), new Person("Michael", "Schumacher") }; // 调用Array的Sort泛型方法给Person数组进行首姓名排序 Array.Sort(persons, (p1, p2) => p1.FirstName.CompareTo(p2.FirstName)); // 调用Array的Foreach泛型方法将Person数组的首姓名输出到控制台 Array.ForEach(persons, p => Console.WriteLine("{0}", p.FirstName)); // 调用Array的Foreach泛型方法将Person数组的末姓名输出到控制台 Array.ForEach(persons, p => Console.WriteLine("{0}", p.LastName)); // 调用Array的FindAll泛型方法查找首字母以S开头的Person类集合 Person[] sPersons = Array.FindAll(persons, p => p.LastName.StartsWith("S")); // 调用Array的ConvetAll泛型方法将一种类型数组转换为另一种类型数组 Racer[] racers = Array.ConvertAll<Person, Racer>(persons, p => new Racer(String.Format("{0} {1}", p.FirstName, p.LastName))); Console.ReadLine(); } } }
从上面的例子看出Array类的泛型方法还是很强大的。