扩展方法&泛型的变化

扩展方方法

在不改动已经建立的类的基础上给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");
        }
    }

静态类注意事项

  1. 不能建立对象,相似抽像类
  2. 不能被继承,相似sealed;
  3. 不能声明非静态字段

可选实参和命名实参

  • 可选实参
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关键字web

    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关键字
    泛型参数从父类对象转换成子类类型c#

    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关键字 只有在程序执行过程当中才能肯定类型
    与隐式类型不一样 隐式类型在编译时就能根据值推断出类型。ide

    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);
        }
    }

这部份内容的使用频率不高,若是以为有用的话就顶一下。若是有错误的地方,就请多指教。谢谢