C#基础语法00

一、C# 介绍

cloud:   Arue

WEB:    ASP.NET

C# 刘铁猛学习笔记基础

UP:龙马008

【net6微服务】新手入门,一层一层拨开微服务核心的神秘面纱,让你豁然开朗!服务注册/网关/故障处理/集中鉴权_哔哩哔哩_bilibili

【WPF入门】WPF零基础到精通,从概念到实操,步步提升!_哔哩哔哩_bilibili

新阁教育:

1、各模块介绍与命名空间

2、基本元素

3、方法与调用

4、操作符与表达式

5、数据类型

5.1、字符串

5.2、结构体

在 C# 中,结构体(struct)是一种值类型(value type),用于组织和存储相关数据。

在 C# 中,结构体是值类型数据结构,这样使得一个单一变量可以存储各种数据类型的相关数据。

struct 关键字用于创建结构体

5.3、数组

5.4、集合

5.5、枚举

5.6、列表

5.7、字典

5.8、集合

5.9、泛型

泛型

泛型(Generic) 允许您延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。

泛型方法

   class Program
    {
        static void Swap<T>(ref T lhs, ref T rhs)
        {
            T temp;
            temp = lhs;
            lhs = rhs;
            rhs = temp;
        }
        static void Main(string[] args)
        {
            int a, b;
            char c, d;
            a = 10;
            b = 20;
            c = 'I';
            d = 'V';

            // 在交换之前显示值
            Console.WriteLine("Int values before calling swap:");
            Console.WriteLine("a = {0}, b = {1}", a, b);
            Console.WriteLine("Char values before calling swap:");
            Console.WriteLine("c = {0}, d = {1}", c, d);

            // 调用 swap
            Swap<int>(ref a, ref b);
            Swap<char>(ref c, ref d);

            // 在交换之后显示值
            Console.WriteLine("Int values after calling swap:");
            Console.WriteLine("a = {0}, b = {1}", a, b);
            Console.WriteLine("Char values after calling swap:");
            Console.WriteLine("c = {0}, d = {1}", c, d);
            Console.ReadKey();
        }
    }

泛型委托

delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static int AddNum(int p)
        {
            num += p;
            return num;
        }

        public static int MultNum(int q)
        {
            num *= q;
            return num;
        }
        public static int getNum()
        {
            return num;
        }

        static void Main(string[] args)
        {
            // 创建委托实例
            NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
            NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
            // 使用委托对象调用方法
            nc1(25);
            Console.WriteLine("Value of Num: {0}", getNum());
            nc2(5);
            Console.WriteLine("Value of Num: {0}", getNum());
            Console.ReadKey();
        }
    }

泛型的类型

5.10、常量

public const int a=10;  //常量不可更改,必须立刻幅值

常量不可改,不能用类或者结构体类型作为结构体类型

此时可用静态只读字段:

public static readonly Build location new Build("some");

只读:向外暴露不允许更改的数据:只读属性

为了提高程序的可读性和执行效率:常量

为了防止对象的值被改变:只读字段

5.11、值类型与引用类型

枚举和结构体为值类型

引用类型: 类、委托、数组、字符串、dynamic、接口

  • 结构是值类型(Value Type): 结构是值类型,它们在栈上分配内存,而不是在堆上。当将结构实例传递给方法或赋值给另一个变量时,将复制整个结构的内容。
  • 类是引用类型(Reference Type): 类是引用类型,它们在堆上分配内存。当将类实例传递给方法或赋值给另一个变量时,实际上是传递引用(内存地址)而不是整个对象的副本。

6、类

这类前边的修饰符:

static

类: 封装修饰符   

方法: 封装修饰符+ (virtual或 override)+ 返回值  方法名(传入形参).

委托:delegate,与方法定义类似,前边加了封装类型和delegate修饰

事件:基于委托的事件: 相当于指针

接口:可以实现多继承

6.1、字段

6.2、属性

刘铁猛:C#语言入门详解017字段、属性、索引器、常量_哔哩哔哩_bilibili

基础看刘铁猛:

只读方法:只读属性

class Student
{
    private int age ;
    public int Age 
    {
        get{return age;}   #  无set
    }
}

外部不能访问: set加了private

class Student
{
    private int age ;
    public int Age 
    {
        get{return age;}   # 
        private set{age=value;}
    }
}

属性:对内保护字段不被污染,对外;暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的。

6.3 方法

6.3.1、构造方法

6.3.2、析构方法

using System;
namespace LineApplication
{
   class Line
   {
      private double length;   // 线条的长度
      public Line()  // 构造函数
      {
         Console.WriteLine("对象已创建");
      }
      ~Line() //析构函数
      {
         Console.WriteLine("对象已删除");
      }

      public void setLength( double len )
      {
         length = len;
      }
      public double getLength()
      {
         return length;
      }

      static void Main(string[] args)
      {
         Line line = new Line();
         // 设置线条长度
         line.setLength(6.0);
         Console.WriteLine("线条的长度: {0}", line.getLength());           
      }
   }
}

6.3.3、扩展方法

扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型

扩展方法必须是静态的、共有的被public  static修饰的

必需是形参列表中的第一个,由this修饰;

必需由一个静态类(一般类名为SomeTypeExtension)来统一收纳对SomeType类型的扩展方法;

举例:LINQ方法;

   internal class Program
   {
       static void Main(string[] args)
       {
           double x = 3.14159;
           double y = x.Round(4);   //  扩展方法
       }
   }
   static class DoubleExtension
   {
       public static double Round(this double input,int digits)  //  加个this变为扩展方法
       {
           double result =Math.Round(input ,digits);
           return result;
       }
   }

6.4、封装

访问级别:piblic   private ,protected 

readonly

一个 访问修饰符 定义了一个类成员的范围和可见性。C# 支持的访问修饰符如下所示:

  • public:所有对象都可以访问,同一个解决方案都可访问,实现跨项目访问。
  • private:对象本身在对象内部可以访问。
  • protected:只有该类对象及其子类对象可以访问,可以跨项目在子类里边调用,无法在子类外调用。
  • internal:同一个程序集的对象可以访问,即是同一个项目里都可访问
  • protected internal:访问限于当前程序集或派生自包含类的类型。

如果没有指定访问修饰符,则使用类成员的默认访问修饰符,即为 private

类无修饰符默认为 internal

sealed 、abstract、

6.5 、继承

子类继承父类:全盘继承:字段、属性,方法、嵌套类、委托、事件。构造器不被继承

继承链上的类,先创建父类,再逐级创建子类

子类构造方法与父类构造方法类似,形参和返回值类型和个数一样。

子类不继承父类构造方法的实例:

    internal class Program
    {
        static void Main(string[] args)
        {
        }
    }
    class Vehicle
    {
        public Vehicle(string owner)
        {
            this.Owner = owner;
        }
        public string Owner { get; set; }
    }
    class Car : Vehicle
    {
        public Car(string owner) : base(owner)
        {
            this.Owner = owner;
        }
        public void ShowOwner()
        {
            Console.WriteLine(Owner);
        }
    }

可以继承父类方法:包括带返回值和形参的方法

    internal class Program
    {
        public static void Main(string[] args)
        {
            //  父类可以声明 子类的实例化对象
            Vehicle v =new Car();
            v.Run();
            Car car = new Car();
            car.Fuel("123");
        }
    }
    class Vehicle
    {
        public virtual void Run()
        {
            Console.WriteLine("I'm running");
            //System.out.printIn("I'm running");
            
        }
        public void Fuel(string s)
        {
            Console.WriteLine(s);
        }
    }
    class Car : Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("I'm Car");    
        }
    }
    class RaseCar : Car
    {
        public void Run()
        {
            Console.WriteLine("I'm RaseCar");
        }
    }

在C#中,如果你用父类声明一个变量,并试图用子类去实例化这个变量,那么你只能访问该父类中声明的方法和属性。这个变量在编译时被视为父类类型,因此它只能调用父类中定义的方法和属性。

尽管在运行时这个变量实际上引用的是子类对象,但由于变量是父类类型,你仍然不能通过该变量直接调用子类新增的方法和属性。如果你尝试这样做,编译器会报错,因为它无法确定在父类类型的变量上调用子类特有的方法是否安全。

如果你需要调用子类特有的方法,你需要将该变量显式转换为子类类型。但是,在进行这样的转换之前,你应该检查该变量是否真的引用了一个子类对象,否则你可能会得到一个 InvalidCastException 异常。这通常通过 is 或 as 关键字来实现

class Parent  
{  
    public void ParentMethod()  
    {  
        Console.WriteLine("Parent method called.");  
    }  
}  
  
class Child : Parent  
{  
    public void ChildMethod()  
    {  
        Console.WriteLine("Child method called.");  
    }  
}  
  
class Program  
{  
    static void Main()  
    {  
        Parent parentVar = new Child(); // 父类变量引用子类对象  
        parentVar.ParentMethod(); // 可以调用父类方法  
  
        // parentVar.ChildMethod(); // 编译错误,因为parentVar是父类类型  
  
        // 安全转换并调用子类方法  
        if (parentVar is Child childVar)  
        {  
            childVar.ChildMethod(); // 现在可以调用子类方法  
        }  
        else  
        {  
            Console.WriteLine("parentVar is not a Child instance.");  
        }  
    }  
}

只有当用IKill声明的new WarmKiller()实例化  才能调用 void IKiller.Kill()方法

   internal class Program
   {
       static void Main(string[] args)
       {
           //  只有当用IKill声明的new WarmKiller()实例化  才能调用 void IKiller.Kill()方法
           IKiller killer = new WarmKiller();
           killer.Kill();
       }
   }
   interface IGentleman
   {
       void Love();
   }
   interface IKiller
   {
       void Kill();
   }
   class WarmKiller:IGentleman,IKiller 
   { 
       public void Love()
       {
           Console.WriteLine("I will love you for ever...");
         
       }
       void IKiller.Kill()
       {
           Console.WriteLine("I'm a Killer");
       }
   }

6.6、多态

父类对象可以声明子类对象,但是这个变量不能调用子类有父类没有的成员,即智能调用父类中的方法和成员;

多态是同一个行为具有多个不同表现形式或形态的能力。方法重写

多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。

    internal class Program
    {
        static void Main(string[] args)
        {
            //  父类可以声明 子类的实例化对象
            Vehicle v =new Car();
            v.Run();
        }
    }
    class Vehicle
    {
        public virtual void Run()
        {
            Console.WriteLine("I'm running");
        }
    }
    class Car : Vehicle
    {
        public override void Run()
        {
            Console.WriteLine("I'm Car");    
        }
    }

6.7、抽象类和部分类

Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。

抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

1、抽象类

抽象类里边可以定义普通方法和抽象方法:

  public abstract class BaseClass
    {
        public abstract void Eat(); // 抽象方法-吃饭
        public abstract void Walk(); // 抽象方法-走路
        public abstract void Speak(); // 抽象方法-说话

    }

2、部分类

部分类即把类的定义放在多个文件中,如将字段、属性和构造函数放在一个文件中,而把方法放在另一个文件中。

为此,只需在包含部分类定义的每个文件中对类使用partial关键字即可

引用:C#类——部分类_c# 部分类-CSDN博客

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApplication1
{
   partial class MyClass
    {
       public void ShowName()
       {
           Console.WriteLine("姓名: 梦断难寻");
       }
    }
}

部分类2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApplication1
{
   partial class MyClass
    {
       public void ShowSex()
       {
           Console.WriteLine("性别: 男");
       }
    }
}

在主题方法中使用这个类program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass My = new MyClass();
            My.ShowName();
            My.ShowAge();
            My.ShowSex();
        }
    }
}

6.8、开闭原则

7、事件、委托、接口

7.1、事件

1、事件 event

作用:为了程序的逻辑更加有道理、更加安全,谨防借刀杀人

事件的本质是委托字段的一个包装器,对委托和字段起限制作用,事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能。

先声明事件:再用+=订阅事件,,声明事件需要先声明

能够发生的事件:事件的订阅

事件多用于桌面、手机等开发的客户端编程,这些程序经常是用户通过事件来驱动的

事件的订阅者,事件的接收者,事件的响应者,事件的处理者,被事件所通知的对象

事件信息、事件消息,事件数据,事件参数

MVC、MVP、MVVM是事件更高级、更高效的”玩法“

事件的拥有者、成员、响应者、

事件的处理器:本质是一个回调方法

事件订阅:将事件处理器与事件关联在一起,本质上是以一种委托类型为基础的约定

在类的内部声明事件,首先必须声明该事件的委托类型

两个事件处理器, 

已有事件的订阅

    internal class Program
    {
        static void Main(string[] args)
        {
            Timer timer =new Timer();
            timer.Interval = 1000;
            Boy boy = new Boy();
            Girl girl = new Girl();
            timer.Elapsed += boy.Action;   //  订阅事件 +=
            timer.Elapsed += girl.Action;

            timer.Start();
            Console.ReadLine();
        }
    }
    class Boy
    {
        internal void Action(object sender,ElapsedEventArgs e)
        {
            Console.WriteLine("Jump!");
        }
    }
    class Girl
    {
        internal void Action(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("Jump112!");
        }
    }

例二:已有事件的订阅

    internal class Program
    {
        static void Main(string[] args)
        {
            Form form = new Form();
            Controller controller = new Controller(form);  // 事件响应者
            form.ShowDialog();


        }
        class Controller
        {
            private Form form;
            public Controller(Form form)
            {
                if (form != null)
                {
                    this.form = form;
                    this.form.Click += this.FormClicked ;   //  订阅事件
                }
            }
            private void FormClicked(object sender,EventArgs e)  // 事件处理器
            {
                this.form.Text = DateTime.Now.ToString();
            }
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            MyForm form = new MyForm();
            form.Click  += form.FormClicked;
            form.ShowDialog();
        }
    }
    class MyForm : Form
    {
        internal void FormClicked(object sender,EventArgs e)
        {
            this.Text = DateTime.Now.ToString();
        }

    }
   internal class Program
   {
       static void Main(string[] args)
       {
           MyForm form = new MyForm();
           form.ShowDialog();
       }
   }
   class MyForm : Form
   {
       private TextBox textBox;
       private Button button;
       public MyForm()
       {
           this.textBox = new TextBox();
           this.button = new Button();
           this.Controls.Add(this.button);
           this.Controls.Add(this.textBox);
           this.button.Click += this.ButtonClicked;
           this.button.Text = "Say Hello";
           this.button.Top = 100;
       }
       private void ButtonClicked(object sender,EventArgs e)
       {
           this.Text = DateTime.Now.ToString();
           this.textBox.Text = "Hello World!!";
       }

   }
       public Form1()
       {
           InitializeComponent();
           // this.myButton.Click += new EventHandler(this.ButtonClicked);   //  订阅委托指向的方法
           this.myButton.Click += delegate (object Sender, EventArgs e) { 
               this.mytextBox.Text = "haha"; };   //  此类委托
       }
       private void ButtonClicked(object sender, EventArgs e)
       {
           this.mytextBox.Text = "Hello World";
       }

上述为已有事件的委托:

2、自定义的事件:

先声明事件:再用+=订阅事件,,声明事件需要先声明,事件定义后可以直接订阅,无需像类和委托那样需要声明一个变量。

能够发生的事件:事件的订阅

using System;
namespace SimpleEvent
{
  using System;
  /***********发布器类***********/
  public class EventTest
  {
    private int value;
    //  声明委托
    public delegate void NumManipulationHandler();


    public event NumManipulationHandler ChangeNum;
    protected virtual void OnNumChanged()
    {
      if ( ChangeNum != null )
      {
        ChangeNum(); /* 事件被触发 */
      }else {
        Console.WriteLine( "event not fire" );
        Console.ReadKey(); /* 回车继续 */
      }
    }


    public EventTest()
    {
      int n = 5;
      SetValue( n );
    }


    public void SetValue( int n )
    {
      if ( value != n )
      {
        value = n;
        OnNumChanged();
      }
    }
  }


  /***********订阅器类***********/

  public class subscribEvent
  {
    public void printf()
    {
      Console.WriteLine( "event fire" );
      Console.ReadKey(); /* 回车继续 */
    }
  }

  /***********触发***********/
  public class MainClass
  {
    public static void Main()
    {
      EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
      subscribEvent v = new subscribEvent(); /* 实例化对象 */
      e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 注册 */
      e.SetValue( 7 );
      e.SetValue( 11 );
    }
  }
}

输出:

event not fire
event fire
event fire

定义的事件:事件基于委托,自定义事件的触发方式

using System;
using System.IO;

namespace BoilerEventAppl
{

   // boiler 类
   class Boiler
   {
      private int temp;
      private int pressure;
      public Boiler(int t, int p)
      {
         temp = t;
         pressure = p;
      }

      public int getTemp()
      {
         return temp;
      }
      public int getPressure()
      {
         return pressure;
      }
   }
   // 事件发布器
   class DelegateBoilerEvent
   {
      public delegate void BoilerLogHandler(string status);

      // 基于上面的委托定义事件
      public event BoilerLogHandler BoilerEventLog;

      public void LogProcess()
      {
         string remarks = "O. K";
         Boiler b = new Boiler(100, 12);
         int t = b.getTemp();
         int p = b.getPressure();
         if(t > 150 || t < 80 || p < 12 || p > 15)
         {
            remarks = "Need Maintenance";
         }
         OnBoilerEventLog("Logging Info:\n");
         OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);
         OnBoilerEventLog("\nMessage: " + remarks);
      }

      protected void OnBoilerEventLog(string message)
      {
         if (BoilerEventLog != null)
         {
            BoilerEventLog(message);   //  事件的触发
         }
      }
   }
   // 该类保留写入日志文件的条款
   class BoilerInfoLogger
   {
      FileStream fs;
      StreamWriter sw;
      public BoilerInfoLogger(string filename)
      {
         fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
      }
      public void Logger(string info)
      {
         sw.WriteLine(info);
      }
      public void Close()
      {
         sw.Close();
         fs.Close();
      }
   }
   // 事件订阅器
   public class RecordBoilerInfo
   {
      static void Logger(string info)
      {
         Console.WriteLine(info);
      }//end of Logger

      static void Main(string[] args)
      {
         BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");
         DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();
         boilerEvent.BoilerEventLog += new 
         DelegateBoilerEvent.BoilerLogHandler(Logger);
         boilerEvent.BoilerEventLog += new 
         DelegateBoilerEvent.BoilerLogHandler(filelog.Logger);   //  上一行与本行为同一段代码
         boilerEvent.LogProcess();
         Console.ReadLine();
         filelog.Close();
      }//end of main

   }//end of RecordBoilerInfo
}

例三:

另一种事件的定义: 类似于将委托指向方法

基于委托定义事件:  EventHandler微软自定义的委托

声明委托与实例化委托,定义类和实例化类,实例化和定义结构体

    internal class Program
    {
        static void Main(string[] args)
        {
            Customer customer =new Customer();
            Waiter waiter =new Waiter();
            customer.Order += waiter.Action;   // 添加事件
            customer.Order-= waiter.Action;   //  移除事件
            customer.Action();
            customer.PayTheBill();


        }
    }
    public class OrderEventArgs:EventArgs
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }
    //  定义委托
    public delegate void OrderEventHandler(Customer customer,OrderEventArgs e);    //  定义委托
    
    public class Customer
    {   
        //  实例化委托
        private OrderEventHandler orderEventHandler;  //  
        // 定义事件
        public event OrderEventHandler Order
        {
            add { this.orderEventHandler += value; }
            remove
            {
                this.orderEventHandler -=value;
            }
        }
        public double Bill { get; set; }
        public void PayTheBill()
        {
            Console.WriteLine("I will pay bill {0}", this.Bill);
        }
        public void WalkIn()
        {
            Console.WriteLine("wALK INTO THE RESTAURANT");
        }
        public void SitDown()
        {
            Console.WriteLine("Sit down");
        }
        public void Think()
        {
            for(int i = 0; i < 5; i++)
            {
                Console.WriteLine("Let me think...");
                Thread.Sleep(1000);
            }
            if(this.orderEventHandler!= null)  //  事件触发
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = "Kongpao Chicken";
                e.Size = "large";
                this.orderEventHandler.Invoke(this,e);   //  事件执行
            }
        }
        public void Action()
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown(); 
            this.Think();   
        }
    }
    public class Waiter
    {
        public void Action(Customer customer, OrderEventArgs e)
        {
            Console.WriteLine("I will server you the dish{0}", e.DishName);
            double price = 10;
            switch (e.Size)
            {
                case "small":
                    price = price * 0.5;
                    break;
                case "large":
                    price = price * 1.5;
                    break;
                default:
                    break;
            }
        }
    }

另一种定义事件:此时的事件定义(声明)和上述不同

       public event OrderEventHandler Order;
       protected void OnOrder(string dishName,string size)
       {
           if (this.Order != null)
           {
               OrderEventArgs e = new OrderEventArgs();
               e.DishName = dishName;
               e.Size = size;
               this.Order.Invoke(this, e);
           }
       }

7.2、委托

函数指针升级版:委托指向函数

定义委托,声明委托,实例化委托,定义、声明、实例化类或者结构体

1、Action和Func

用法:Invoke为执行,,执行的两种方式:Invoke或者Invoke去掉,对于Func、Action和delegate自定义的都适用。

同样对于事件的执行也同样适用,具体参见事件:自定义事件的一些例子:例三

    internal class Program
    {
        static void Main(string[] args)
        {
            Cal1 cal = new Cal1();
            Action action = new Action(cal.Report);  // 不加括号,加了为调用
            action.Invoke();  //  间接调用  ,执行Report这个函数
            action();  //  第二种调用方式 执行Report这个函数
            //  Func委托带返回值
            Func<int ,int,int> fun1= new Func<int,int,int>(cal.Add);
            int x = 1;
            int y = 2;
            int z = 0;
            //  两种调用方式
            z = fun1(x, y);
            z = fun1.Invoke(x, y);
        }
    }
    class Cal1
    {
        public void Report()
        {
            Console.WriteLine("I have 3methods");
        }
        public int Add(int a, int b)
        {
            int result = a + b;
            return result;
        }
        public int Sub(int a, int b)
        {
            int result = a - b;
            return result;
        }
    }

上述为Action和Func委托,Invoke执行, 

Func

Func至少0个输入参数,至多16个输入参数,根据返回值泛型返回。必须有返回值,不可void。

Func<int> 表示没有输入参参,返回值为int类型的委托。

Func<object,string,int> 表示传入参数为object, string ,返回值为int类型的委托。

Func<object,string,int> 表示传入参数为object, string, 返回值为int类型的委托。

Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型),返回值为int类型的委托。

Action

 Action委托至少0个参数,至多16个参数,无返回值

Action 表示无参,无返回值的委托。

Action<int,string> 表示有传入参数int,string无返回值的委托。

Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托。

Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托。

委托指向方法

2、自定义委托

delegate:

当你使用 += 操作符将一个方法分配给委托时,你实际上是在创建一个委托实例(如果之前不存在的话),并将该实例添加到委托的调用列表中。如果委托已经有一个或多个方法与之关联,那么新添加的方法会被添加到调用列表的末尾,而不是替换现有的方法。

using System;  
  
public delegate void MyDelegate(string message);  
  
public class Program  
{  
    public static void Main()  
    {  
        // 创建一个委托变量  
        MyDelegate myDelegate = null;  
  
        // 将方法1分配给委托  
        myDelegate += Method1;  
  
        // 将方法2也分配给同一个委托  
        myDelegate += Method2;  
  
        // 调用委托,这将依次调用方法1和方法2  
        myDelegate?.Invoke("Hello, world!");  
    }  
  
    // 方法1,与委托签名匹配  
    public static void Method1(string message)  
    {  
        Console.WriteLine("Method 1 called: " + message);  
    }  
  
    // 方法2,也与委托签名匹配  
    public static void Method2(string message)  
    {  
        Console.WriteLine("Method 2 called: " + message);  
    }  
}

需要注意的是,委托是引用类型,因此如果没有将任何方法分配给委托(即委托为 null),则调用委托(如 myDelegate.Invoke(...))将会导致 NullReferenceException。在上面的例子中,我使用了 myDelegate?.Invoke("Hello, world!") 来安全地调用委托,这样如果委托为 null,则不会调用任何方法,也不会抛出异常。

委托是一种类,类是数据类型所以委托也是一种数据类型

它的生命方式与一般的类不同,注意委托的位置,别是嵌套类

委托与所封装的方法必需“类型兼容”

参数列表上在个数和数据类型上一致

    public delegate double Calc(double x, double y);
    internal class Program
    {
        static void Main(string[] args)
        {
            Cal1 cal1=new Cal1();
            Calc calc1 = new Calc(cal1.Add);
            double a = 100;
            double b = 200;
            double c = 0;
            c=calc1.Invoke(a,b);
            Console.WriteLine(c);
        }
    }
    class Cal1
    {
        public void Report()
        {
            Console.WriteLine("I have 3methods");
        }
        public double Add(double a, double b)
        {
            double result = a + b;
            return result;
        }
        public int Sub(int a, int b)
        {
            int result = a - b;
            return result;
        }
    }

模板方法和回调方法:

分门别类,有利于重复使用,只需要不断增减产品工厂的个数,其他打包方法不用动

    //  定义委托
    public delegate double Calc(double x, double y);
    internal class Program
    {
        static void Main(string[] args)
        {
            Cal1 cal1=new Cal1();  
            Calc calc1 = new Calc(cal1.Add);  //  声明和实例化委托
            double a = 100;
            double b = 200;
            double c = 0;
            c=calc1.Invoke(a,b);
            Console.WriteLine(c);

            ProductFactory productFactory = new ProductFactory();
            WrapFactory wrapFactory = new WrapFactory();
            Func<Product> func1 = new Func<Product>(productFactory.MakePizza);  //  绑定一个方法
            Func<Product> func2 = new Func<Product>(productFactory.MakeToyCar);

            Logger logger = new Logger();
            Action<Product> log = new Action<Product>(logger.Log);

            Box box1 = wrapFactory.WrapProduct(func1,log);   //  传入委托类型形参,传入的是副本,地址
            Box box2 = wrapFactory.WrapProduct(func2,log);
            Console.WriteLine(box1.Product.Name);

        }
       

    }

    class Logger
    {
        public void Log(Product product)
        {
            Console.WriteLine("Product{0} created at {1}.Price is {2}", product.Name, DateTime.UtcNow, product.Price);
        }
    }

    class Product
    {
        public string Name { get; set; }
        public int Price { get; set; }
    }
    class Box
    {
        public Product Product { get; set; }  //  属性
    }
    class WrapFactory
    {
        public Box WrapProduct(Func<Product> getProduct,Action<Product> logCallback)  // 传入的是委托方法,输出为Product的委托指向的方法
        {
            Box box = new Box();
            Product product = getProduct.Invoke();
            logCallback.Invoke(product);
            box.Product = product;
            return box;
        }
    }
    class ProductFactory
    {
        public Product MakePizza()  //  方法
        {
            Product product = new Product();
            product.Name = "Pizza";
            product.Price = 12;
            return product;
        }
        public Product MakeToyCar()
        {
            Product product = new Product();
            product.Name = "Toy Car";
            product.Price = 200;
            return product;
        }
    }
    class Cal1
    {
        public void Report()
        {
            Console.WriteLine("I have 3methods");
        }
        public double Add(double a, double b)
        {
            double result = a + b;
            return result;
        }
        public int Sub(int a, int b)
        {
            int result = a - b;
            return result;
        }
    }

委托警示:

    internal class Program
    {
        static void Main(string[] args)
        {
            Operation opt1 = new Operation();
            Operation opt2 = new Operation();
            Operation opt3 = new Operation();
            opt1.InnerOperation = opt2;
            opt2.InnerOperation = opt1;
            opt3.Operate(new object(), null, null);
            //  问题一:如果传入的两个参数为null,失败和成功的效果是什么?答案: 内层的 操作会调用外层的回调!
            //  问题二:如果传入的参数不为null,会出现什么情况? 答案:所有默认callback都被穿透性屏蔽。

        }
    }
    class Operation
    {
        //  Action是C#中的一个预定义委托,它表示一个没有参数且没有返回值(即返回类型为void)的方法
        //  定义委托
        public Action DefaultSuccessCallback { get; set; }
        public Action DefaultFailureCallback { get; set; }
        public Operation InnerOperation { get; set; }
        public object Operate(object input,Action successCallback,Action failureCallback)
        {
            if (successCallback == null)
            {
                successCallback = this.DefaultSuccessCallback;
            }
            if (failureCallback == null)
            {
                failureCallback=this.DefaultFailureCallback;
            }
            object result = null;
            try
            {
                result = this.InnerOperation.Operate(input, successCallback, failureCallback);

            }
            catch
            {
                failureCallback.Invoke();
            }
            successCallback.Invoke();
            return result;
        }
    }

多播委托和异步调用

Invoke是同步调用

BegainInvoke是异步调用

    internal class Program
    {
        static void Main(string[] args)
        {
            Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };
            Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };
            Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Red};
            Action action1 = new Action(stu1.DoHomework);
            Action action2 = new Action(stu2.DoHomework);
            Action action3 = new Action(stu3.DoHomework);
            // action1.Invoke();
            // action2.Invoke();
            // action3.Invoke();
            // action1 += action2;
            // action1 += action3;
            //action1.Invoke();   //  多播方法,封装多个委托
            // 隐式异步调用,线程加速,下面三个同时运行
            //action1.BeginInvoke(null,null);
            //action2.BeginInvoke(null, null);
            //action3.BeginInvoke(null, null);
            //  显示异步调用,,Thread  可换成  Task
            Thread thread1 = new Thread(new ThreadStart(stu1.DoHomework));
            Thread thread2 = new Thread(new ThreadStart(stu2.DoHomework));
            Thread thread3 = new Thread(new ThreadStart(stu3.DoHomework));
            thread1.Start();
            thread2.Start();
            thread3.Start();
        }
    }
    class Student
    {
        public int ID { get; set; }
        public ConsoleColor PenColor { get; set; }
        public void DoHomework()
        {
            for(int i=0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student{0} doing homework {1} hour(s)",this.ID,i);
                Thread.Sleep(1000);

            }
        }
    }

显示异步调用

Invoke是同步调用

BeginInvoke是显示异步调用,Thread和Task,,同时执行

匿名委托

// 使用匿名委托
MyDelegate delegateInstance = delegate (string message) { Console.WriteLine(message); };
delegateInstance("Hello, Anonymous Delegate!");

应用接口取代委托

Lamda表达式委托

// 使用 Lambda 表达式
MyDelegate delegateInstance = message => Console.WriteLine(message);
delegateInstance("Hello, Lambda Delegate!");

7.3、接口

interface:

接口是为解耦而生:“高内聚,低耦合”,方便单元测试;

接口是一个“协约”

接口和抽象类都不能实例化,只能用来声明变量、引用具体类(concrete class)的实例

接口的封装修饰符为public  ,所以省略不写;

接口实现自由替换:为解耦而生,接口不实现具体方法,,为继承而用。

   internal class Program
   {
       static void Main(string[] args)
       {
           Console.WriteLine("I'm a boy");
           var engine = new Engine();
           var car = new Car(engine);
           car.Run(3);
           Console.WriteLine(car.Speed);
           var user= new PhoneUser(new NokiaPhone());  //  可以实现替换
           user.UserPhone();
       }
   }
   class PhoneUser
   {
       private IPhone _phone;
       public PhoneUser(IPhone phone)
       {
           _phone = phone;
       }
       public void UserPhone()
       {
           _phone.Dail();
           _phone.PickUp();
           _phone.Receive();
           _phone.Send ();
       }
   }
   interface IPhone
   {
       void Dail();
       void PickUp();
       void Send();
       void Receive();
   }
   class NokiaPhone : IPhone
   {
       public void Dail()
       {
           Console.WriteLine("Hi This's Tim!");
       }

       public void PickUp()
       {
           Console.WriteLine("Hi This's Pick!");
       }

       public void Receive()
       {
           Console.WriteLine("Hi This's Receive!");
       }

       public void Send()
       {
           Console.WriteLine("Hi This's Send!");
       }
   }

 只有当用IKill声明的new WarmKiller()实例化  才能调用 void IKiller.Kill()方法

   internal class Program
   {
       static void Main(string[] args)
       {
           //  只有当用IKill声明的new WarmKiller()实例化  才能调用 void IKiller.Kill()方法
           IKiller killer = new WarmKiller();
           killer.Kill();
       }
   }
   interface IGentleman
   {
       void Love();
   }
   interface IKiller
   {
       void Kill();
   }
   class WarmKiller:IGentleman,IKiller 
   { 
       public void Love()
       {
           Console.WriteLine("I will love you for ever...");
         
       }
       void IKiller.Kill()
       {
           Console.WriteLine("I'm a Killer");
       }
   }

强制类型转换  is  或者as  都行

7.4、依赖反转

7.5、依赖注入

1、简介

使用依赖注入,不需要在代码里主动地创建或者获取对象B,相反,只需要在构造器参数里声明需要对象B的引用。

不使用依赖注入的案例:

    public class ClassA
    {
        private readonly ClassB _classB;

        public ClassA()
        {
            _classB = new ClassB(); //主动创建对象B
        }

        public void Process()
        {
            _classB.DoSomething();
            ...
        }
    }

    public class ClassB
    {
        public void DoSomething()
        {
           ...
        }
    }

不使用依赖注入,必须在代码的某个地方主动地创建或者获取对象B。

使用依赖注入的:

 public class ClassA
    {
        private readonly ClassB _classB;

        public ClassA(ClassB classB) // 声明构造器里需要对象B引用,依赖注入框架就会自动注入对象B
        {
            _classB = classB;
        }

        public void Process()
        {
            _classB.DoSomething();
            ...
        }
    }

    public class ClassB
    {
        public void DoSomething()
        {
           ...
        }
    }

    // 伪代码: 向依赖注入系统中注册 ClassA 和 ClassB
    DependencyInjectionSystem.AddType(ClassA);
    DependencyInjectionSystem.AddType(ClassB);

下述代码使用的是 Microsoft.Extensions.DependencyInjection 命名空间下的依赖注入功能,这是 ASP.NET Core 和 .NET Core 框架中提供的。ServiceCollection 和 IServiceProvider 等类是这些现代框架的核心部分,它们不是 .NET Framework 的一部分。

因此,上述代码不能直接在 .NET Framework 项目中执行。如果您尝试在 .NET Framework 项目中引入 Microsoft.Extensions.DependencyInjection 程序集,您会发现它不兼容,因为这是一个专门为 .NET Core 和 ASP.NET Core 设计的库。

最后,请注意,即使您可以在 .NET Framework 项目中使用依赖注入,但由于框架之间的差异,某些 ASP.NET Core 特定的功能(如中间件、内置的身份验证和授权等)将不可用。因此,在决定如何实施依赖注入时,请考虑您的项目的具体需求和限制。

导入这个引用:using Microsoft.Extensions.DependencyInjection;和安装相应NuGet包

2、依赖注入

通过这个依赖注入可以将heavyTank改为mediumTank

在 ASP.NET Core 中,可以使用依赖注入容器注册和解析基类类型并注入子类对象

需要把所有设计的依赖关系通过AssScoped注册完成

重点学习依赖注入两种注册方式: 泛型方式和typeof方式

//  第一种
sc.AddScoped(typeof(ITank), typeof(HeavyTank));
// 第二种
sc.AddScoped<ITank, HeavyTank>();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Authentication.ExtendedProtection;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;


namespace _12反射_1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var driver = new Driver(new HeavyTank());

            driver.Drive();
            //  
            ITank tank = new HeavyTank();
            var t = tank.GetType();
            object o = Activator.CreateInstance(t);
            MethodInfo fireMi = t.GetMethod("Fire");
            MethodInfo runMi = t.GetMethod("Run");
            fireMi.Invoke(o, null);
            runMi.Invoke(o, null);
            //  上述
            var sc = new ServiceCollection();
            sc.AddScoped(typeof(ITank), typeof(HeavyTank));
            // var sp = sc.BuildServiceProvider();
            // sc.AddScoped<ITank, typeof(HeavyTank>();
            // 使用 BuildServiceProvider 方法从 ServiceCollection 构建一个 IServiceProvider 实例  
            //  此时应用Microsoft.Extensions.DependencyInjection NuGet程序包就可以,安装这个包,BuildServiceProvider就不会报红
            //IServiceProvider sp = sc.BuildServiceProvider();
            //ITank tank1 =sp.GetService<ITank>();
            //tank.Fire();
            //tank.Run();    //  
            //  随意替换体现依赖注入的优点
            sc.AddScoped(typeof(IVehicle), typeof(Car));
            sc.AddScoped(typeof(Driver));   //  或者另一种注册方式  sc.AddScoped<Driver>();
            var sp = sc.BuildServiceProvider();
            Driver driver1= sp.GetService<Driver>();
            driver1.Drive();



        }
    }

    class Driver
    {
        private ITank _vehicle;
        public Driver(ITank vehicle)
        {
            _vehicle = vehicle;
        }
        public void Drive()
        {
            _vehicle.Run();
        }
    }
    interface IVehicle
    {
        void Run();
    }
    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Car is running...");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Truck is running...");
        }
    }
    interface IWeapon
    {
        void Fire();
    }
    interface ITank:IVehicle,IWeapon
    {
        void Fire();
        void Run();
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Kall..");
        }
    }
    class MediumTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Kamedium..");
        }
    }
    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Kaheavy..");
        }
    }
    
    
}

3、外部dll:

调用外部链接库,并继承

var assembly=AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
                var types = assembly.GetTypes();
// See https://aka.ms/new-console-template for more information
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Loader;

namespace BabyStroller.App
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");

            var folder = Path.Combine(Environment.CurrentDirectory, "animal");
            var files = Directory.GetFiles(folder);
            var animalTypes=new List<Type>();
            foreach (var file in files)
            {
                var assembly=AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
                var types = assembly.GetTypes();
                foreach (var t in types)
                {
                    if (t.GetMethod("Voice") != null)
                    {
                        animalTypes.Add(t);
                    }
                }
            }
            while (true)
            {
                for(int i=0; i < animalTypes.Count; i++)
                {
                    Console.WriteLine($"{i+1}.{animalTypes[i].Name}");
                }
                Console.WriteLine("======");
                Console.WriteLine("Please choose animal");
                int index = int.Parse(Console.ReadLine());  
                if (index > animalTypes.Count || index < 1)
                {
                    Console.WriteLine("No sun an animal.Try again!");
                    continue;
                }
                Console.WriteLine("How many times?");
                int times = int.Parse(Console.ReadLine());
                var t = animalTypes[index - 1];
                var m = t.GetMethod("voice");
                var o =Activator.CreateInstance(t);
                m.Invoke(o, new object[] { times });   //  委托
            }


        }
        

    }
}


这点难以理解先放着后续再看

7.6、接口隔离

不同功能的接口分开定义,再继承

7.7、单元测试

单元测试   Xunit;

    public class UnitTest1
    {
        [Fact]
        public void PowerSupplyLowerThanZero_OK()
        {
            var fan = new DeskFan(new PowerSupplyLowerThanZero());
            var expected = "Won't work";
            var actual = fan.Work();
            Assert.Equal(expected, actual);


        }
    }
    class PowerSupplyLowerThanZero : IPowerSupply  //  public  修饰才行
    {
        public int GetPower()
        {
            return 0;
        }

    }

利用Moq资源

    public class UnitTest1
    {
        [Fact]
        public void PowerSupplyLowerThanZero_OK()
        {
            //var fan = new DeskFan(new PowerSupplyLowerThanZero());
            //var expected = "Won't work";
            // var actual = fan.Work();
            //Assert.Equal(expected, actual);
            //  单元测试
            var mock = new Mock<IPowerSupply>();
            mock.Setup(ps=>ps.GetPower()).Returns(() => 0);
            var fan = new DeskFan(mock.Object);
            var expected = "Won't work";
            var actual = fan.Work();
            Assert.Equal(expected, actual);

        }
    }
    class PowerSupplyLowerThanZero : IPowerSupply  //  public  修饰才行
    {
        public int GetPower()
        {
            return 0;
        }

    }

8、特性、反射

8.1、特性

特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性

    internal class Program
    {
        static void Main(string[] args)
        {
            var driver = new Driver(new HeavyTank());

            driver.Drive();
            //  
            ITank tank = new HeavyTank();
            var t = tank.GetType();
            object o = Activator.CreateInstance(t);
            MethodInfo fireMi = t.GetMethod("Fire");
            MethodInfo runMi = t.GetMethod("Run");
            fireMi.Invoke(o, null);
            runMi.Invoke(o, null);
            //  上述
            var sc = new ServiceCollection();
            sc.AddScoped(typeof(ITank), typeof(HeavyTank));
            // var sp = sc.BuildServiceProvider();
            // 使用 BuildServiceProvider 方法从 ServiceCollection 构建一个 IServiceProvider 实例  
            //  此时应用Microsoft.Extensions.DependencyInjection NuGet程序包就可以,安装这个包,BuildServiceProvider就不会报红
            IServiceProvider serviceProvider = sc.BuildServiceProvider();


        }
    }

    class Driver
    {
        private ITank _vehicle;
        public Driver(ITank vehicle)
        {
            _vehicle = vehicle;
        }
        public void Drive()
        {
            _vehicle.Run();
        }
    }
    interface IVehicle
    {
        void Run();
    }
    class Car : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Car is running...");
        }
    }
    class Truck : IVehicle
    {
        public void Run()
        {
            Console.WriteLine("Truck is running...");
        }
    }
    interface IWeapon
    {
        void Fire();
    }
    interface ITank:IVehicle,IWeapon
    {
        void Fire();
        void Run();
    }
    class LightTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Ka..");
        }
    }
    class MediumTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Ka..");
        }
    }
    class HeavyTank : ITank
    {
        public void Fire()
        {
            Console.WriteLine("Boom.");
        }
        public void Run()
        {
            Console.WriteLine("Ka Ka Ka..");
        }
    }

8.2、反射

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。

您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性

9.、综合

lamda  Linq

9.1、泛型

1、方法泛型

代码:

        static void Swap<T>(ref T lhs, ref T rhs)
        {
            T temp;
            temp = lhs;
            lhs = rhs;
            rhs = temp;
        }
        static void Main(string[] args)
        {
            int a, b;
            char c, d;
            a = 10;
            b = 20;
            c = 'I';
            d = 'V';

            // 在交换之前显示值
            Console.WriteLine("Int values before calling swap:");
            Console.WriteLine("a = {0}, b = {1}", a, b);
            Console.WriteLine("Char values before calling swap:");
            Console.WriteLine("c = {0}, d = {1}", c, d);

            // 调用 swap
            Swap<int>(ref a, ref b);
            Swap<char>(ref c, ref d);

2、委托泛型

delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static int AddNum(int p)
        {
            num += p;
            return num;
        }

        public static int MultNum(int q)
        {
            num *= q;
            return num;
        }
        public static int getNum()
        {
            return num;
        }

        static void Main(string[] args)
        {
            // 创建委托实例
            NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
            NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
            // 使用委托对象调用方法
            nc1(25);
            Console.WriteLine("Value of Num: {0}", getNum());
            nc2(5);
            Console.WriteLine("Value of Num: {0}", getNum());
            Console.ReadKey();
        }
    }
}

9.2、索引器

用来检索集合

1、语法:

element-type this[int index] 
{
   // get 访问器
   get 
   {
      // 返回 index 指定的值
   }

   // set 访问器
   set 
   {
      // 设置 index 指定的值 
   }
}

2、列表实例:

using System;
namespace IndexerApplication
{
   class IndexedNames
   {
      private string[] namelist = new string[size];
      static public int size = 10;
      public IndexedNames()
      {
         for (int i = 0; i < size; i++)
         namelist[i] = "N. A.";
      }
      public string this[int index]
      {
         get
         {
            string tmp;

            if( index >= 0 && index <= size-1 )
            {
               tmp = namelist[index];
            }
            else
            {
               tmp = "";
            }

            return ( tmp );
         }
         set
         {
            if( index >= 0 && index <= size-1 )
            {
               namelist[index] = value;
            }
         }
      }

      static void Main(string[] args)
      {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         for ( int i = 0; i < IndexedNames.size; i++ )
         {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

3、字典实例索引器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _01索引器
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Student stu =new Student();
            var mathscore = stu["123"];
        }
    }
    class Student   //  索引器
    {
        private Dictionary<string,int> scoreDictionary= new Dictionary<string,int>();
        public int? this[string subject]
        {
            get
            {
                if(this.scoreDictionary.ContainsKey(subject))
                {
                    return this.scoreDictionary[subject];
                }
                else
                {
                    return null;
                }
            }
            set
            {
                //  检测是否有值
                if(value.HasValue==false)
                {
                    throw new Exception("Score cannot be null ");
                }

                if (this.scoreDictionary.ContainsKey(subject))
                {
                    this.scoreDictionary[subject] = value.Value;
                }
                else
                {
                    this.scoreDictionary.Add(subject, value.Value);
                
                }

            }
        }

    }
}

9.3、方法形参

C#语言入门详解018传值 输出 引用 数组 具名 可选参数,扩展方法_哔哩哔哩_bilibili

引用类型:

1、值参数

声明时不带修饰符的形参是值形参,一个值形参对应于一个局部变量,

值参数创建变量的副本,复制

值类型传值参数

引用类型传值参数

被赋予新值: 值参数创建副本不影响外部变量的值

    internal class Program
    {
        static void Main(string[] args)
        {
            Student1 stu =new Student1() { Name="Tom"};
            SomeMethod(stu);
            Console.WriteLine(stu.Name);  // 输出Tom
        }

        static void SomeMethod(Student1 stu)
        {
            stu = new Student1() { Name = "Tim" };  //  实例化一个新地址
            Console.WriteLine(stu.Name);   //  输出  Tim
        }
    }
    class Student1{ public string Name{ get;set;}}

b被修改:引用类型不创建新的存储位置

    internal class Program
    {
        static void Main(string[] args)
        {
            Student1 stu =new Student1() { Name="Tom"};
            SomeMethod(stu);
            Console.WriteLine(stu.Name);  // 输出Tim
        }

        static void SomeMethod(Student1 stu)  //  传进来的是地址
        {
            stu.Name = "Tim";
            Console.WriteLine(stu.Name);   //  输出  Tim
        }
    }
    class Student1{ public string Name{ get;set;}}

2、out ref

ref引用形参

引用参数不创建变量的副本,引用参数还是那个堆地址,和值参数创建副本不一样

        static void Main(string[] args)
        {
            int a = 1;
            Add(ref a);
            Console.WriteLine(a);   //  a=2
        }

        static void Add(ref int a)
        {
            a = a + 1;
        }

ref  传入的是地址,ref  修饰符显示指出改变实际参数的值

地址和值均改变了,

    internal class Program
    {
        static void Main(string[] args)
        {
            Student1 outstu =new Student1() { Name="Tom"};
            Console.WriteLine(outstu.Name);  // 输出Tom
            SomeMethod(ref outstu);
            //  下面输出地址和值均改变了,值为Tim
            Console.WriteLine("HashCode{0},{1}",outstu.GetHashCode(),outstu.Name);  
        }

        static void SomeMethod(ref Student1 stu)
        {
            stu = new Student1() { Name = "Tim" };  //  实例化一个新地址
            Console.WriteLine(stu.Name);   //  输出  Tim
        }
    }
    class Student1{ public string Name{ get;set;}}

引用类型,存储的是一个地址,通过地址取索引值,参数和变量指向同一个地址,堆内存上的地址,堆上的值改变,变量的地址改变   堆和栈,地址

ref修饰传入形参后,引用类型与传入形参

实例:验证引用类型与值类型的引用形参的区别

new引用类型,,实例化时创建一种新地址以及新变量,新地址存储,,ref 变量不生成副本,还是同一个,指向是一样的,但是只想里边的地址,    ref改变引用形参 

        static void Main(string[] args)
        {
            Student1 outstu = new Student1() { Name = "Tom" };
            Console.WriteLine("{0},{1}", outstu.GetHashCode(), outstu.Name);
            SomeMethod(outstu);
            Console.WriteLine(outstu.Name);
            int a = 1;
            Add(ref a);
            Console.WriteLine("{0},{1}",outstu.GetHashCode(),outstu.Name);
        }
 

        static void SomeMethod(Student1 stu)
        {
            stu = new Student1() { Name = "Tim" };
            //stu.Name = "Tom";
            Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);
        }

        static void Add(ref int a)
        {
            a = a + 1;
            // Console.WriteLine("{0},{1}", a.GetHashCode(), a);
        }
        class Student1 { public string Name { get; set; } }

out输出形参

输出形参并不创建变量的副本

方法体内必须要有对输出变量的赋值的操作

适用out修饰符显式指出-副作用时通过参数向外输出值

变量在作为输出形参传递之前可以不一定需要明确赋值,

但是在方法返回之前必须赋值

值类型

        static void Main(string[] args)
        {
            Console.WriteLine("please input first number:");
            string arg = Console.ReadLine();
            double x = 0;
            bool b1 = double.TryParse(arg, out x);
            Console.WriteLine(x);
            if (b1 == false)
            {
                Console.WriteLine("input error");
                return;
            }
            Console.WriteLine("please input first number:");
            string arg1 = Console.ReadLine();
            double y= 0;
            bool b2 = double.TryParse(arg1, out y);
            Console.WriteLine(y);
            if (b2 == false)
            {
                Console.WriteLine("input error");
                return;
            }
        }

输出形参,out引用类型的,不创建副本

        class Student
        {
            public int Age { get; set; }
            public string Name { get; set; }
        }

        class StudentFactory
        {
            public static bool Create(string stuName,int stuAge,out Student result)
            {
                result = null;
                if (string.IsNullOrEmpty(stuName))
                {
                    return false;
                }
                if (stuAge < 20 || stuAge > 80)
                {
                    return false;
                }
                result = new Student(){ Age = stuAge, Name = stuName };
                return true;
         }

不创建副本

3、形参数组

params修饰符

      static void Main(string[] args)
      {
          string str = "Tim;Tom,Amy.Lisa";
          str.Split(';', ',', '.');
          int result = CalSun(1, 2, 3);
          Console.WriteLine(result);
      }
      static int CalSun(params int[] intarray)
      {
          int sum = 0;
          foreach (var item in intarray)
          {
              sum += item;
          }
          return sum;
      }

只能有一个params参数

必须是形参列表中的最后一个方法,由params修饰,String.Format方法和String.Split方法;

具名参数

     static void Main(string[] args)
     {
         string str = "Tim;Tom,Amy.Lisa";
         str.Split(';', ',', '.');
         int result = CalSun(1, 2, 3);
         Console.WriteLine(result);
         PrintInfo(age: 34, name: "Tim");   //  具名参数
     }
     static int CalSun(params int[] intarray)
     {
         int sum = 0;
         foreach (var item in intarray)
         {
             sum += item;
         }
         return sum;
     }
     static void PrintInfo(string name,int age)
     {
         Console.WriteLine("Hello{0},you are {1}", name, age);
     }



可选参数

static string GetStr(string s = "a", int i = 10, string r = "rrrr")
        {
            return s + i + r;
        }

调用方法:

         	   GetStr();
            GetStr("abcde");
            GetStr("abcde", 100);
            GetStr("abcde", 100, "hjklmn");



9.4、lamda表达式

1、简介

(输入参数)=>

2、异步Lamda

通过使用 async 和 await 关键字,你可以轻松创建包含异步处理的 lambda 表达式和语句。其中async 和 await 关键字是在 C# 5 中引入的。

9.5、匿名方法

匿名方法(Anonymous methods) 提供了一种传递代码块作为委托参数的技术。匿名方法是没有名称只有主体的方法。

在匿名方法中您不需要指定返回类型,它是从方法主体内的 return 语句推断的。

using System;

delegate void NumberChanger(int n);
namespace DelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static void AddNum(int p)
        {
            num += p;
            Console.WriteLine("Named Method: {0}", num);
        }

        public static void MultNum(int q)
        {
            num *= q;
            Console.WriteLine("Named Method: {0}", num);
        }

        static void Main(string[] args)
        {
            // 使用匿名方法创建委托实例
            NumberChanger nc = delegate(int x)
            {
               Console.WriteLine("Anonymous Method: {0}", x);
            };
            
            // 使用匿名方法调用委托
            nc(10);

            // 使用命名方法实例化委托
            nc =  new NumberChanger(AddNum);
            
            // 使用命名方法调用委托
            nc(5);

            // 使用另一个命名方法实例化委托
            nc =  new NumberChanger(MultNum);
            
            // 使用命名方法调用委托
            nc(2);
            Console.ReadKey();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值