C# 3.0的新特性
C# 3.0的新特性
个人感觉所有的新特性都是围绕LINQ的,所以LINQ应该是今后的重头戏
还需好好好钻研
自动化属性
对象初始化器
Lambda表达式
本地类型推断
扩展方法
匿名类
查询表达式
一、本地类型推断
使用var关键字定义变量而不是特定的类型关键字
var a = 2; // a is declared as int
object b = 2; // Boxing an int into an object
int c = a; // No cast, no unboxing
int d = (int) b; // Cast is required, an unboxing is done
当使用var定义变量时,编译器常常通过初始化变量表达式
var是定义匿名类变量的唯一的方法
var变量不能定义成员变量和参数变量类型
如: 以下四种方式是不可以的
class VarDemo {
// invalid token 'var' in class, struct or interface member declaration
var k =0;
// type expected in parameter list
public void InvalidUseParameter( var x ){}
// type expected in result type declaration
public var InvalidUseResult() {
return 2;
}
public void InvalidUseLocal() {
var x; // Syntax error, '=' expected
var y = null; // Cannot infer local variable type from 'null'
}
// …
}
二、Lambda 表达式
一种更加简明的方式定义匿名方法
举个例子:
public class AggDelegate {
public List<int> Values;
delegate T Func<T>( T a, T b );
static T Aggregate<T>( List<T> l, Func<T> f ) {
T result = default(T);
bool firstLoop = true;
foreach( T value in l ) {
if (firstLoop) {
result = value;
firstLoop = false;
}
else {
result = f( result, value );
}
}
return result;
}
public static void Demo() {
AggDelegate l = new AggDelegate();
int sum;
使用匿名方法:
sum = Aggregate(
l.Values,
delegate( int a, int b ) { return a + b; }
);
Console.WriteLine( "Sum = {0}", sum );
}
// …
}
使用Lambda表达式:
sum = Aggregate(
l.Values,
( int a, int b ) => { return a + b; }
);
sum = Aggregate(
l.Values,
( a, b ) => { return a + b; }
);
sum = Aggregate(
l.Values,
( a, b ) => a + b
);
int sum = 0;
sum = AggregateSingle(
l.Values,
( x ) => sum += x
);
当lambda表达式中的参数只有一个时,如上所示
则可以将参数两边的括号去掉
int sum = 0;
sum = AggregateSingle(
l.Values,
x => sum += x
);
如果没有参数则括号必须写
( int a, int b ) => { return a + b; } // Explicitly typed, statement body
( int a, int b ) => a + b; // Explicitly typed, expression body
( a, b ) => { return a + b; } // Implicitly typed, statement body
( a, b ) => a + b // Implicitly typed, expression body
( x ) => sum += x // Single parameter with parentheses
x => sum += x // Single parameter no parentheses
() => sum + 1 // No parameters
Predicate 和 Projection
这两个名称是指Lambda表达式不同用途的叫法
Predicate:一个bool表达式
( age ) => age > 21
Projection:返回和唯一的参数不同类型的值
( s ) => s.Length
一个Predicate的例子
public static void Demo() {
string[] names = { "Marco", "Paolo", "Tom" };
Display( names, s => s.Length > 4 );
}
public static void Display<T>( T[] names, Func<T, bool> filter ){
foreach( T s in names) {
if (filter( s )) Console.WriteLine( s );
}
}
一个Lambda表达式也可以分配给以下委托类型的变量
public delegate T Func< T >();
public delegate T Func< A0, T >( A0 arg0 );
public delegate T Func<A0, A1, T> ( A0 arg0, A1 arg1 );
public delegate T Func<A0, A1, A2, T >( A0 arg0, A1 arg1, A2 arg2 );
public delegate T Func<A0, A1, A3, T> ( A0 arg0, A1 arg1, A2 arg2, A3 arg3 );
上面这些委托已经存在于System.Linq命名空间中
但是如果将一个lambda表达式转换成一个Expression Tree,编译器将在执行时把lambda表达式转换成二进制可执
行代码
Expression Tree是System.Linq.Expressions.Expression<T>类的实例
三、扩展方法
使用添加新方法的方式扩展已存在的类型,而不是通过继承的方式
举个例子:
static class ExtensionMethods {
public static void Demo() {
decimal x = 1234.568M;
Console.WriteLine( x.FormattedUS() );
Console.WriteLine( x.FormattedIT() );
Console.WriteLine( FormattedUS( x ) ); // Traditional call allowed
Console.WriteLine( FormattedIT( x ) ); // Traditional call allowed
}
static CultureInfo formatUS = new CultureInfo( "en-US" );
static CultureInfo formatIT = new CultureInfo( "it-IT" );
public static string FormattedUS( this decimal d ){
return String.Format( formatIT, "{0:#,0.00}", d );
}
public static string FormattedIT( this decimal d ){
return String.Format( formatUS, "{0:#,0.00}", d );
}
}
一个扩展方法必须存在于一个static类中,而且本身也必须是public static的
最终要的是this关键字,存在于方法定义时,第一个参数类型的前面,第一个参数的类型就是要扩展的类型
注意:最好是扩展值类型,而不要扩展引用类型,考虑到相关的性能消耗会比较大
扩展方法最通用的用法在自定义的命名空间定义static类,使用using关键子导入到代码中
如果实例方法和扩展方法名字相同时,实例方法的优先级要高
经典实例
public class A {
public virtual void X() {}
}
public class B : A {
public override void X() {}
public void Y() {}
}
static public class E {
static void X( this A a ) {}
static void Y( this A b ) {}
public static void Demo() {
A a = new A();
B b = new B();
A c = new B();
a.X(); // Call A.X
b.X(); // Call B.X
c.X(); // Call B.X
a.Y(); // Call E.Y
b.Y(); // Call B.Y
c.Y(); // Call E.Y
}
}
四、对象初始化表达式
使用一种简化的方式初始化类,如:
// Implicitly calls default constructor before object initialization
Customer customer = new Customer { Name = "Marco", Country = "Italy" };
// Explicitly specify constructor to call before object initialization
Customer c1 = new Customer() { Name = "Marco", Country = "Italy" };
// Explicitly specify nondefault constructor
Customer c2 = new Customer( "Paolo", 21 ) { Country = "Italy" };
嵌套调用初始化表达式
Rectangle r = new Rectangle {
TL = new Point { X = 0, Y = 1 },
BR = new Point { X = 2, Y = 3 }
};
自身对象的初始化(即,在类自身中使用初始化表达式)
Rectangle r = new Rectangle {
TL = { X = 0, Y = 1 },
BR = { X = 2, Y = 3 }
};
集合初始化器
List<int> integers = new List<int> { 1, 3, 9, 18 };
List<Customer> list = new List<Customer> {
new Customer( "Jack", 28 ) { Country = "USA"},
new Customer { Name = "Paolo" },
new Customer { Name = "Marco", Country = "Italy" },
};
五、匿名类型
Customer c1 = new Customer { Name = "Marco" };
var c2 = new Customer { Name = "Paolo" };
var c3 = new { Name = "Tom", Age = 31 };
var c4 = new { c2.Name, c2.Age };
var c5 = new { c1.Name, c1.Country };
var c6 = new { c1.Country, c1.Name };
c1 is Customer
c2 is Customer
c3 is <>f__AnonymousType0`2[System.String,System.Int32]
c4 is <>f__AnonymousType0`2[System.String,System.Int32]
c5 is <>f__AnonymousType5`2[System.String,System.String]
c6 is <>f__AnonymousTypea`2[System.String,System.String]
var ints = new[] { 1, 2, 3, 4 };
var ca1 = new[] {
new Customer { Name = "Marco", Country = "Italy" },
new Customer { Name = "Tom", Country = "USA" },
new Customer { Name = "Paolo", Country = "Italy" }
};
var ca2 = new[] {
new { Name = "Marco", Sports = new[] { "Tennis", "Spinning"} },
new { Name = "Tom", Sports = new[] { "Rugby", "Squash", "Baseball" } },
new { Name = "Paolo", Sports = new[] { "Skateboard", "Windsurf" } }
};
查询表达式
var customers = new []{
new { Name = "Marco", Discount = 4.5 },
new { Name = "Paolo", Discount = 3.0 },
new { Name = "Tom", Discount = 3.5 }
};
var query =
from c in customers
where c.Discount > 3
orderby c.Discount
select new { c.Name, Perc = c.Discount / 100 };
foreach( var x in query ) {
Console.WriteLine( x );
}
结果是:
{ Name = Tom, Perc = 0.035 }
{ Name = Marco, Perc = 0.045 }
转换成C# 3.0 的语法后:
var query = customers
.Where( c => c.Discount > 3)
.OrderBy( c => c.Discount )
.Select( c=> new { c.Name, Perc = c.Discount / 100 } );
真是越到后来越没信心了,毕竟第一次接触LINQ,还得继续努力啊
个人感觉所有的新特性都是围绕LINQ的,所以LINQ应该是今后的重头戏
还需好好好钻研
自动化属性
对象初始化器
Lambda表达式
本地类型推断
扩展方法
匿名类
查询表达式
一、本地类型推断
使用var关键字定义变量而不是特定的类型关键字
var a = 2; // a is declared as int
object b = 2; // Boxing an int into an object
int c = a; // No cast, no unboxing
int d = (int) b; // Cast is required, an unboxing is done
当使用var定义变量时,编译器常常通过初始化变量表达式
var是定义匿名类变量的唯一的方法
var变量不能定义成员变量和参数变量类型
如: 以下四种方式是不可以的
class VarDemo {
// invalid token 'var' in class, struct or interface member declaration
var k =0;
// type expected in parameter list
public void InvalidUseParameter( var x ){}
// type expected in result type declaration
public var InvalidUseResult() {
return 2;
}
public void InvalidUseLocal() {
var x; // Syntax error, '=' expected
var y = null; // Cannot infer local variable type from 'null'
}
// …
}
二、Lambda 表达式
一种更加简明的方式定义匿名方法
举个例子:
public class AggDelegate {
public List<int> Values;
delegate T Func<T>( T a, T b );
static T Aggregate<T>( List<T> l, Func<T> f ) {
T result = default(T);
bool firstLoop = true;
foreach( T value in l ) {
if (firstLoop) {
result = value;
firstLoop = false;
}
else {
result = f( result, value );
}
}
return result;
}
public static void Demo() {
AggDelegate l = new AggDelegate();
int sum;
使用匿名方法:
sum = Aggregate(
l.Values,
delegate( int a, int b ) { return a + b; }
);
Console.WriteLine( "Sum = {0}", sum );
}
// …
}
使用Lambda表达式:
sum = Aggregate(
l.Values,
( int a, int b ) => { return a + b; }
);
sum = Aggregate(
l.Values,
( a, b ) => { return a + b; }
);
sum = Aggregate(
l.Values,
( a, b ) => a + b
);
int sum = 0;
sum = AggregateSingle(
l.Values,
( x ) => sum += x
);
当lambda表达式中的参数只有一个时,如上所示
则可以将参数两边的括号去掉
int sum = 0;
sum = AggregateSingle(
l.Values,
x => sum += x
);
如果没有参数则括号必须写
( int a, int b ) => { return a + b; } // Explicitly typed, statement body
( int a, int b ) => a + b; // Explicitly typed, expression body
( a, b ) => { return a + b; } // Implicitly typed, statement body
( a, b ) => a + b // Implicitly typed, expression body
( x ) => sum += x // Single parameter with parentheses
x => sum += x // Single parameter no parentheses
() => sum + 1 // No parameters
Predicate 和 Projection
这两个名称是指Lambda表达式不同用途的叫法
Predicate:一个bool表达式
( age ) => age > 21
Projection:返回和唯一的参数不同类型的值
( s ) => s.Length
一个Predicate的例子
public static void Demo() {
string[] names = { "Marco", "Paolo", "Tom" };
Display( names, s => s.Length > 4 );
}
public static void Display<T>( T[] names, Func<T, bool> filter ){
foreach( T s in names) {
if (filter( s )) Console.WriteLine( s );
}
}
一个Lambda表达式也可以分配给以下委托类型的变量
public delegate T Func< T >();
public delegate T Func< A0, T >( A0 arg0 );
public delegate T Func<A0, A1, T> ( A0 arg0, A1 arg1 );
public delegate T Func<A0, A1, A2, T >( A0 arg0, A1 arg1, A2 arg2 );
public delegate T Func<A0, A1, A3, T> ( A0 arg0, A1 arg1, A2 arg2, A3 arg3 );
上面这些委托已经存在于System.Linq命名空间中
但是如果将一个lambda表达式转换成一个Expression Tree,编译器将在执行时把lambda表达式转换成二进制可执
行代码
Expression Tree是System.Linq.Expressions.Expression<T>类的实例
三、扩展方法
使用添加新方法的方式扩展已存在的类型,而不是通过继承的方式
举个例子:
static class ExtensionMethods {
public static void Demo() {
decimal x = 1234.568M;
Console.WriteLine( x.FormattedUS() );
Console.WriteLine( x.FormattedIT() );
Console.WriteLine( FormattedUS( x ) ); // Traditional call allowed
Console.WriteLine( FormattedIT( x ) ); // Traditional call allowed
}
static CultureInfo formatUS = new CultureInfo( "en-US" );
static CultureInfo formatIT = new CultureInfo( "it-IT" );
public static string FormattedUS( this decimal d ){
return String.Format( formatIT, "{0:#,0.00}", d );
}
public static string FormattedIT( this decimal d ){
return String.Format( formatUS, "{0:#,0.00}", d );
}
}
一个扩展方法必须存在于一个static类中,而且本身也必须是public static的
最终要的是this关键字,存在于方法定义时,第一个参数类型的前面,第一个参数的类型就是要扩展的类型
注意:最好是扩展值类型,而不要扩展引用类型,考虑到相关的性能消耗会比较大
扩展方法最通用的用法在自定义的命名空间定义static类,使用using关键子导入到代码中
如果实例方法和扩展方法名字相同时,实例方法的优先级要高
经典实例
public class A {
public virtual void X() {}
}
public class B : A {
public override void X() {}
public void Y() {}
}
static public class E {
static void X( this A a ) {}
static void Y( this A b ) {}
public static void Demo() {
A a = new A();
B b = new B();
A c = new B();
a.X(); // Call A.X
b.X(); // Call B.X
c.X(); // Call B.X
a.Y(); // Call E.Y
b.Y(); // Call B.Y
c.Y(); // Call E.Y
}
}
四、对象初始化表达式
使用一种简化的方式初始化类,如:
// Implicitly calls default constructor before object initialization
Customer customer = new Customer { Name = "Marco", Country = "Italy" };
// Explicitly specify constructor to call before object initialization
Customer c1 = new Customer() { Name = "Marco", Country = "Italy" };
// Explicitly specify nondefault constructor
Customer c2 = new Customer( "Paolo", 21 ) { Country = "Italy" };
嵌套调用初始化表达式
Rectangle r = new Rectangle {
TL = new Point { X = 0, Y = 1 },
BR = new Point { X = 2, Y = 3 }
};
自身对象的初始化(即,在类自身中使用初始化表达式)
Rectangle r = new Rectangle {
TL = { X = 0, Y = 1 },
BR = { X = 2, Y = 3 }
};
集合初始化器
List<int> integers = new List<int> { 1, 3, 9, 18 };
List<Customer> list = new List<Customer> {
new Customer( "Jack", 28 ) { Country = "USA"},
new Customer { Name = "Paolo" },
new Customer { Name = "Marco", Country = "Italy" },
};
五、匿名类型
Customer c1 = new Customer { Name = "Marco" };
var c2 = new Customer { Name = "Paolo" };
var c3 = new { Name = "Tom", Age = 31 };
var c4 = new { c2.Name, c2.Age };
var c5 = new { c1.Name, c1.Country };
var c6 = new { c1.Country, c1.Name };
c1 is Customer
c2 is Customer
c3 is <>f__AnonymousType0`2[System.String,System.Int32]
c4 is <>f__AnonymousType0`2[System.String,System.Int32]
c5 is <>f__AnonymousType5`2[System.String,System.String]
c6 is <>f__AnonymousTypea`2[System.String,System.String]
var ints = new[] { 1, 2, 3, 4 };
var ca1 = new[] {
new Customer { Name = "Marco", Country = "Italy" },
new Customer { Name = "Tom", Country = "USA" },
new Customer { Name = "Paolo", Country = "Italy" }
};
var ca2 = new[] {
new { Name = "Marco", Sports = new[] { "Tennis", "Spinning"} },
new { Name = "Tom", Sports = new[] { "Rugby", "Squash", "Baseball" } },
new { Name = "Paolo", Sports = new[] { "Skateboard", "Windsurf" } }
};
查询表达式
var customers = new []{
new { Name = "Marco", Discount = 4.5 },
new { Name = "Paolo", Discount = 3.0 },
new { Name = "Tom", Discount = 3.5 }
};
var query =
from c in customers
where c.Discount > 3
orderby c.Discount
select new { c.Name, Perc = c.Discount / 100 };
foreach( var x in query ) {
Console.WriteLine( x );
}
结果是:
{ Name = Tom, Perc = 0.035 }
{ Name = Marco, Perc = 0.045 }
转换成C# 3.0 的语法后:
var query = customers
.Where( c => c.Discount > 3)
.OrderBy( c => c.Discount )
.Select( c=> new { c.Name, Perc = c.Discount / 100 } );
真是越到后来越没信心了,毕竟第一次接触LINQ,还得继续努力啊