扩展方方法
在不改动已经创建的类的基础上给Person类添加一个print()方法,这时就要用到扩展方法 只能在非嵌套非泛型的类中定义扩展方法
//实现扩展方法的类必须是静态类
public static class PersonExtern
{
//扩展方法中至少有一个参数,这个参数前要加this,this后边是要扩展的类对象
//必须使用this
public static void print(this Person p)
{
Console.WriteLine("name:{0},age:{1}", p.Name, p.Age);
}
}
不止可以给自定义的类实现扩展方法,也可以为系统提供的类实现扩展方法.
第一个参数是扩展到类的对象,从第二个参数开始就扩展方法的参数。不同的封闭泛型有自己的静态成员,所以不同的封闭泛型有自己的扩展方法。
public static int sum(this List<int> l,int n)
{
int s=0;
for(int i=0;i<n;i++)
{
s+=l[i];
}
return s;
}
Person p=new Person();
p.print();//对象在调用方法时,首先在该类中查找方法,没找到就在当前命名空间中查找扩展方法,如果当前命名空间下没有,再去其他命名空间下查找
//扩展方法也可以重载,在调用时根据参数选择调用不同的扩展方法
如果参数也一样,则只能存在于不同的命名空间中
public static class PersonExtend
{
public static void print(this Person p)
{
Console.WriteLine("i am the extend");
}
public static void print(this Person p,string s)
{
Console.WriteLine("i am thi extend");
}
}
class Program
{
public static void Main()
{
Person p = new Person();
p = null;
p.print();//空引用可以调用扩展方法,但是不能调用实例方法
p.print("ren");
//p.show();
Student s = new Student();
s.print();
}
}
public class Person
{
public Person()
{
}
public void show()
{
}
}
public static class PersonExten
{
public static void print(this Person s)
{
Console.WriteLine("i am the exten ");
}
public static void print(this Person s,string str)
{
Console.WriteLine("i am the exten" + str);
}
}
public class Student:Person
{
public void show()
{
}
}
所以如果给object 类添加一个方法则所有的类都能调用到该方法 但是不要这样使用
public static class ObjectExten
{
public static void fun(this object o)
{
Console.WriteLine("objectExtern");
}
}
静态类注意事项
- 不能创建对象,类似抽像类
- 不能被继承,类似sealed;
- 不能声明非静态字段
可选实参和命名实参
- 可选实参
class Program
{
public static void Main()
{
int m=add(9, 1);
Console.WriteLine(m);
int n = add();//不给add()传参就计算两个默认值的和
Console.WriteLine(n);
int x = add2(100);//两个形参都有默认值,只传一个参数会赋值给第一个参数
Console.WriteLine(x);
}
//声明形参时,给形参添加默认值,调用函数时就可以不传参数,直接使用默认值进行运算
//不传参就使用默认值计算,传参就使用实参计算
public static int add(int x=10,int y=9)
{
return x + y;
}
public static int add2(int x,int y=9)//可选实参必须放在最后边
{
return x+y;
}
}
- 命名实参
public static void Main()
{
//命名实参,指定实参给哪个可选形参赋值
int b = add(b: 1);/通过这个形式给第二个参数传参,只能进行指定传参
Console.WriteLine(b);
}
//数组不能为可选形参 ref或out不能为可选形参
public static int add(int a=10,int b=20)
{
return a + b;
}
private string name;
public Person(string _name="defaultname")//这样也算是一个无参数的构造函数,因为你可以选择不传参数,使用默认值
{
}
public class Student:Person
{
//子类中不显示调用父类构造函数时,会自动调用父类无参的构造函数(或带参的构造函数参数有默认值)
}
泛型的 协变 、逆变
协变 泛型参数从子类类型转换成父类类型。 使用out关键字
class MainClass { public static void Main() { Create<Animal> aInterface = new AnimalFactory(); Animal a = aInterface.create(); Create<Dog> dInterface = new DogFactory(); Dog d = dInterface.create(); aInterface = dInterface;//协变 泛型参数从子类到父类 Animal a2 = aInterface.create();//create返回值从子类到父类 a2.print();//调用的是dog类中的print方法 //Dog对象可以直接赋值给Animal使用,同样,泛型参数是Dog的接口也可以赋值给泛型参数是Animal的接口(泛型接口的类型转换) //dInterface = aInterface;//逆变,泛型参数从父类到子类 //Dog d2 = dInterface.create();//create返回值是Animal对象,不能赋值给Dog引用 //泛型参数作为返回值时,只能发生协变 } } public class Animal { public virtual void print() { Console.WriteLine("animal"); } } public class Dog : Animal { public override void print() { Console.WriteLine("Dog"); } } public interface Create<out T> { T create(); } public class AnimalFactory : Create<Animal> { public Animal create() { return new Animal(); } } public class DogFactory : Create<Dog> { public Dog create() { return new Dog(); } } }
逆变 必须使用in关键字
泛型参数从父类对象转换成子类类型class MainClass { public static void Main() { Animal a = new Animal(); Dog d = new Dog(); Show<Animal> aInterface = new ShowAniaml(); Show<Dog> dInterface = new ShowDog(); aInterface.show(a); dInterface.show(d); dInterface = aInterface;//逆变,泛型参数从父类到子类 dInterface.show(d);//已经将aInerface赋值给dInterface,所以调用的是aInterface的create方法,参数d从子类到父类: show方法的参数是Animal类型,Animal x = d;但是实际调用的是dog类重点print()方法。这点又回归到了多态 //aInterface = dInterface;//协变,泛型参数从子类到父类 //aInterface.show(a);//参数a从父类到子类:show方法的参数是Dog类型,Dog x = a; //泛型参数做参数时,不能协变 //泛型的协变逆变,指泛型参数(泛型接口或泛型委托中的泛型参数)的协变逆变 } } public class Animal { public virtual void print() { Console.WriteLine("Animal"); } } public class Dog : Animal { public override void print() { Console.WriteLine("Dog"); } } public interface Show<in T> { void show(T x); } public class ShowAniaml : Show<Animal> { public void show(Animal x) { x.print(); } } public class ShowDog : Show<Dog> { public void show(Dog x) { x.print(); } } }
总之还是遵循:父类对象可以指向子类对象,子类对象不能指向父类对象。
还有泛型的协变逆变,指泛型参数(泛型接口或泛型委托中的泛型参数)的协变逆变动态类型
使用dynamic关键字 只有在程序执行过程中才能确定类型
与隐式类型不同 隐式类型在编译时就能根据值推断出类型。class Program { public delegate int MyDelegat(int x); public static void Main() { dynamic o = new ExpandoObject(); o.Name="zhang"; o.Age = 24; o.Addmethod = (MyDelegat)(x => x + 1); Console.WriteLine(o.Name + o.Age); } }