命名参数
[TestMethod]
public void Test()
{
//两者等效
FullName(firstName: "王", lastName: "小二");
FullName("王", "小二");
}
public string FullName(string firstName,string lastName)
{
return firstName + lastName;
}
可选参数
注意:可选参数必须放在参数最后的位置
[TestMethod]
public void Test()
{
Optional("王小二");
Optional("王小二", 10);
}
public void Optional(string name, int count=0)
{
Console.WriteLine(name + count);
}
静态构造方法
静态构造函数只会执行一次,在C#中,一般在调用类的任何成员之前调用
class A
{
static A()
{
Console.WriteLine("A");
}
}
[TestMethod]
public void Test()
{
A a = new A();
}
构造函数初始化器
this关键字仅调用参数最匹配的那个构造函数.
可以调用本类的构造函数,也可以调用父类的构造函数,调用父类构造函数时,需使用base关键字。
class B:A
{
private string name;
private string sex;
B(string name)
{
this.name = name;
}
B(string name,string sex):this(name)
{
this.sex = sex;
}
B():base()
{
}
}
只读字段
只读字段只能初始赋值或者在构造函数中赋值,不能在其他地方赋值
class C
{
private readonly string code=string.Empty;
C()
{
code="123";
}
}
匿名类型对象
var doc = new { Name="hh",Age=20};
结构体
值类型,可以不用new 创建,此时分配在栈上。不支持继承,但支持实现接口。
继承于ValueType。
struct C
{
public string Code;
public int Age;
}
弱引用
WeakReference,引用计数器不增加
[TestMethod]
public void Test()
{
WeakReference weakReference = new WeakReference(new string('a',5));
string s;
if (weakReference.IsAlive)
{
s = weakReference.Target as string;
Console.WriteLine(s);
}
else
Console.WriteLine("对象已被回收");
GC.Collect();
Thread.Sleep(5000);
if (!weakReference.IsAlive)
Console.WriteLine("对象已被回收");
else
Console.WriteLine("我还活着");
}
partial类
编译的时候会合并
partial class A //A.cs
{
}
partial class A //B.cs
{
}
静态类
成员都为静态
扩展方法
public static class StringExtension
{
public static void Print(this string s)
{
Console.WriteLine("Foo invoked for {0}", s);
}
}
[TestMethod]
public void Test()
{
"".Print();
}
扩展方法是一种特殊的静态方法,虽然是静态方法,但是可以像使用类型上的实例方法一样去使用扩展方法(调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异)。扩展方法的第一个参数指定该方法作用于哪个类型,并且该参数以this修饰符为前缀。当你在其他命名空间使用时,需要用using将扩展方法所在命名空间显式导入到源代码中。扩展方法必须在非范型静态类中定义。扩展方法无法访问扩展类型中的私有变量。可以使用扩展方法来扩展类或接口, 但不能重写扩展方法。与接口或类方法具有相同名称和签名的扩展方法永远不会调用(这一点要牢记)。编译时, 扩展方法的优先级总是比类型本身中定义的实例方法低。换句话说,如果某个类型具有一个名为Process(int i)的方法,而你有一个具有相同签名的扩展方法,则编译器总是绑定到该实例方法。当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。如果未找到任何匹配方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法。通常建议你只在不得已的情况下才实现扩展方法,并谨慎地实现。只要有可能,必须扩展现有类型的情形都应该通过创建从现有类型派生新类型来达到这一目的。在使用扩展方法来扩展你无法更改其源代码的类型时,你需要承受该类型实现中的更改会导致扩展方法失效的风险。在代码中,可以使用实例方法语法调用扩展方法。但是,编译器生成的中间语言(IL)会将代码转换为对静态方法的调用。因此,并未真正违反封装原则。实际上, 扩展方法无法访问他们所扩展的类型中的私有变量。
抽象类
virtual和abstract关键字
虚方法:
virtual 关键字用于在基类中修饰方法。
virtual的使用会有两种情况:
情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现。
抽象方法的实现必须在派生类中使用override关键字来实现。
属性
属性访问器
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
//自动属性
public string Name{ get; set; }
ref和out关键字
用途:
在C#中通过使用方法来获取返回值时,通常只能得到一个返回值。因此,当一个方法需要返回多个值的时候,就需要用到ref和out。
概述:
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
相同点:
1、都能返回多个返回值。
2、若要使用 ref 和out参数,则方法定义和调用方法都必须显式使用 ref和out 关键字。在方法中对参数的设置和改变将会直接影响函数调用之处(参数的初始值)。
不同点:
1、ref指定的参数在函数调用时候必须初始化,不能为空的引用。而out指定的参数在函数调用时候可以不初始化;
2、out指定的参数在进入函数时会清空自己,必须在函数内部赋初值。而ref指定的参数不需要。
口诀:
ref有进有出,out只出不进。
sealed关键字
当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承。类似于Java中final关键字。
sealed 修饰方法或属性
能够允许类从基类继承,并防止它们重写特定的虚方法或虚属性。
1)sealed是对虚方法或虚属性,也就是同override一起使用,如果不是虚方法或虚属性会报出错误:cannot be sealed because it is not an override
2)防止子类重写特定的方法或属性
public class A
{
protected virtual void M()
{
Console.WriteLine("A.M()");
}
protected virtual void M1()
{
Console.WriteLine("A.M1()");
}
}
public class B : A
{
protected sealed override void M()
{
Console.WriteLine("B.M()");
}
protected override void M1()
{
Console.WriteLine("B.M1()");
}
}
public sealed class C : B
{
/* ConsoleApplication1.MSFun.Sealed.C.M()':
* cannot override inherited member 'ConsoleApplication1.MSFun.Sealed.B.M()'
* because it is sealed */
//protected override void M() { Console.WriteLine("C.M()"); }
protected override void M1()
{
Console.WriteLine("C.M1()");
}
}
可变参数
用params关键字,最少为0个参数
public static int Sum(params int[] arr)
{
int sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
return sum;
}