1. 扩展方法及其使用规则
- 使用扩展方法可以扩展密封类型,无需继承
- 利用扩展方法可以避免出现失控的深度继承层次体系
- 扩展方法是静态类中的静态方法
- 扩展方法第一个参数的类型之前必须使用this修饰符;this指带将要被扩展的类型
- 不支持扩展属性、事件和操作符
- 相对于实例方法而言,扩展方法的可视性要差一些,而且限制也会多一些
- 拓展方法是通过实例语法来调用的
- 拓展方法的优先级比常规方法要低;因此,如果某个类有用一个同名方法的话,那么被调用的将会是实例方法
- 扩展方法得到只能感知的支持
- 泛型扩展方法是得到支持的,事实上,System.Linq命名空间中许多LINQ关键字就是通过这个而实现的
- 扩展方法能在字面量上调用
- 拓展方法可以用在密封类和内部类上,因为扩展方法自动支持装箱和拆箱
- 拓展方法并不是真正的成员,因此只能在其中访问被扩展对象的公共成员
- 拓展方法隐式使用ExtensionAttribute
class Program
{
static void Main(string[] args)
{
var song = new { Artist = "Jussi Bjorling", Song = "Aida" };
song.Dump();
}
}
// 静态类
public static class Dumper
{
// 静态方法
public static void Dump(this Object o)
{
PropertyInfo[] properties = o.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
try
{
Debug.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name, p.GetValue(o, null)));
}
catch
{
Debug.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name, "unk."));
}
}
}
}
2. 带返回值的扩展方法
class Program
{
static void Main(string[] args)
{
var songs = new
{
Artist = "Green Day",
Song = "Wake Me Up When September Ends"
};
Console.WriteLine(songs.Dump());
}
}
public static class Dumper
{
// 带返回值得扩展方法
public static string Dump(this Object o)
{
PropertyInfo[] properties = o.GetType().GetProperties();
StringBuilder builder = new StringBuilder();
foreach (PropertyInfo p in properties)
{
try
{
builder.AppendFormat(string.Format("Name: {0}, Value: {1}", p.Name,p.GetValue(o, null)));
}
catch
{
builder.AppendFormat(string.Format("Name: {0}, Value: {1}", p.Name,"unk."));
}
builder.AppendLine();
}
return builder.ToString();
}
}
3. 带参数得扩展方法
static void Main(string[] args)
{
var song = new
{
Artist = "Avril Lavigne",
Song = "My Happy Ending"
};
song.Dump(Console.Out);
}
public static class Dumper
{
public static void Dump(this Object o, TextWriter writer)
{
PropertyInfo[] properties = o.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
try
{
writer.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name, p.GetValue(o, null)));
}
catch
{
writer.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name, "unk."));
}
}
}
}
4. 重载扩展方法
class Program
{
static void Main(string[] args)
{
var songs = new[]
{
new {Artist="Jussi Bjorling", Song="Aida"},
new {Artist="Sheryl Crow", Song="Steve McQueen"}
};
songs.Dump();
}
}
public static class Dumper
{
public static void Dump(this Object o)
{
PropertyInfo[] properties = o.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
try
{
Debug.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name,p.GetValue(o, null)));
}
catch
{
Debug.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name,"unk."));
}
}
}
public static void Dump(this IList list)
{
foreach (object o in list)
o.Dump();
}
}
5. 泛型扩展方法
class Program
{
static void Main(string[] args)
{
// 连接字符串
string connectionString = "Data Source=CASPAR;Initial Catalog=Northwind;Integrated Security=True";
// 存储结果集合
List<Order> orders = new List<Order>();
// 数据库连接
using (SqlConnection connection = new SqlConnection(connectionString))
{
// 执行查询
SqlCommand command = new SqlCommand("SELECT * FROM ORDERS", connection);
command.CommandType = CommandType.Text;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// 读取查询结果
while (reader.Read())
{
Order order = new Order();
// 根据读取得结果初始化Order实例
order.Read(reader);
// 存储结果
orders.Add(order);
}
}
// 显示结果
orders.Dump(Console.Out);
}
}
/// <summary>Order类得扩展方法,用于读取指定得字段。EntityClass拓展方法根据值是否为空返回不同得值</summary>
public static class ReaderHelper
{
public static void Read(this Order order, IDataReader reader)
{
order.OrderID = order.SafeRead(reader, "OrderID", -1);
order.CustomerID = order.SafeRead(reader, "CustomerID", "");
}
public static T SafeRead<T>(this EntityClass entity,IDataReader reader, string fieldName, T defaultValue)
{
try
{
object o = reader[fieldName];
if (o == null || o == System.DBNull.Value)
return defaultValue;
return (T)Convert.ChangeType(o, defaultValue.GetType());
}
catch
{
return defaultValue;
}
}
}
/// <summary>封装扩展方法得静态类,该类中得拓展方法用于显示信息</summary>
public static class Dumper
{
public static void Dump(this Object o, TextWriter writer)
{
PropertyInfo[] properties = o.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
try
{
writer.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name,p.GetValue(o, null)));
}
catch
{
writer.WriteLine(string.Format("Name: {0}, Value: {1}", p.Name,"unk."));
}
}
}
public static void Dump<T>(this IList<T> list, TextWriter writer)
{
foreach (object o in list)
o.Dump(writer);
}
}
/// <summary>空得实体类,用于演示泛型拓展方法</summary>
public class EntityClass { }
/// <summary>该类继承自实体类</summary>
public class Order : EntityClass
{
public Order(){}
public int OrderID {get;set;}
public string CustomerID {get;set;}
}
6. 拓展方法是如何支持LINQ得
LIQN是一种语法糖,在底层调用的则是对应的拓展方法。
LIQN查询
var numbers = new int[] { 1966, 1967, 1968, 1969, 1970 };
var evens = from num in numbers where num % 2 == 0 select num;
foreach (var result in evens)
Console.WriteLine(result);
拓展方法
var numbers = new int[] { 1966, 1967, 1968, 1969, 1970 };
var evens = numbers.Where(item => item % 2 == 0).Select(item=>item);
foreach (var result in evens)
Console.WriteLine(result);
7. 分部方法
- 分部方法要声明在分部类中
- 分部方法要使用partial修饰符
- 分部方法在声明时不能有方法体
- 分部方法之呢个返回void
- 分部方法可以时静态的,而且可以有参数和参数修饰符
- 分部方法是私有的,不过不能再字面上使用访问修饰符;也就是说,你不能显示使用private关键字
- 编译器忽略未使用的分部方法
class Program
{
static void Main(string[] args)
{
// 复合类型初始化
CustomerList customers = new CustomerList
{
new Customer{CustomerID=1, Name="Levi, Ray and Shoup"},
new Customer{CustomerID=2, Name="General Dynamics Land Systems"},
new Customer{CustomerID=3, Name="Microsoft"}
};
customers.Dump();
}
}
// 分部类
public partial class CustomerList
{
private string propertyName;
private SortDirection direction;
// 分部方法
partial void SpecialSort(string propertyName, SortDirection direction)
{
this.propertyName = propertyName;
this.direction = direction;
Sort(Comparer);
}
/// <summary>
/// Using an integer to change the direction of the sort was a suggestion made by
/// Chris Chartran, my good friend from Canada
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
private int Comparer(Customer x, Customer y)
{
try
{
PropertyInfo lhs = x.GetType().GetProperty(propertyName);
PropertyInfo rhs = y.GetType().GetProperty(propertyName);
int directionChanger = direction == SortDirection.Ascending ? 1 : -1;
object o1 = lhs.GetValue(x, null);
object o2 = rhs.GetValue(y, null);
if (o1 is IComparable && o2 is IComparable)
{
return ((IComparable)o1).CompareTo(o2) * directionChanger;
}
// no sort
return 0;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return 0;
}
}
}
// 分部类
public partial class CustomerList : List<Customer>
{
// 声明分部方法
partial void SpecialSort(string propertyName, SortDirection direction);
public void Dump()
{
SpecialSort("CustomerID", SortDirection.Descending);
foreach (var customer in this)
Console.WriteLine(customer.ToString());
}
}
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("CustomerID={0}, Name={1}", CustomerID, Name);
}
}