文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

c#快速入门~在java基础上,知道C#和JAVA 的不同即可

2023-09-28 17:15

关注

☺ 观看下文前提:如果你的主语言是java,现在想再学一门新语言C#,下文是在java基础上,对比和java的不同,快速上手C#,当然不是说学C#的前提是需要java,而是下文是从主语言是java的情况下,学习C#入门到进阶。


C# 学习参考文档和开发工具



C# 概述

C# 概述

C# 与.Net的关系

  • C# 是由 Anders Hejlsberg 和他的团队在 .Net 框架开发期间开发的
  • C# 程序在 .NET 上运行,而 .NET 是名为公共语言运行时 (CLR) 的虚执行系统和一组类库。 CLR 是 Microsoft 对公共语言基础结构 (CLI) 国际标准的实现。
  • .NET是微软公司下的一个开发平台,.NET核心就是.NET Framwork(.NET框架)是.NET程序开发和运行的环境。
  • 用 C# 编写的源代码被编译成符合 CLI 规范的中间语言 (IL)。 IL 代码和资源(如位图和字符串)存储在扩展名通常为 .dll 的程序集中。 程序集包含一个介绍程序集的类型、版本和区域性的清单。
  • 通过 C# 生成的 IL 代码可以与通过 .NET 版本的 F#、Visual Basic、C++ 生成的代码进行交互。

C# 特性

简单,现代,面向对象类型安全版本控制兼容,灵活


C# 流行原因:


C# 一些重要的功能:




c# 快速入门~C# 和 java 的不同

1、入门demo的hello world

using System;namespace HelloWorldApplication{   class HelloWorld   {      static void Main(string[] args)      {                  Console.WriteLine("Hello World");         Console.ReadKey();      }   }}

☺ 如果是通过 Visual Studio 写的c# 项目:

目录结构:


☺ 对于hello world 程序

(1) using

(2) namespace


2、注释


3、变量命名规范


4、C# 的变量类型:还包含了指针类型

在 C# 中,变量分为以下几种类型:


引用类型:

内置的引用类型有:objectdynamicstring


■ 动态(Dynamic)类型

您可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的。

声明动态类型的语法:dynamic = value;


☺ 字符串(String)类型:还有@ 修饰,@有其相对的意义
String str = "runoob.com";
string str = @"C:\Windows"; //相当于string str = "C:\\Windows";//作用2:使其按照编辑的原格式输出Console.WriteLine(@"你好啊!我的朋友!");Console.ReadKey();//输出结果为:你好啊!我的朋友!   

■ 指针类型(Pointer types)
char* cptr;int* iptr;

■ 用户自定义引用类型有:class、interface 或 delegate。

5、定义常量,使用关键词 const


6、占位符的 {数字}

int n1 = 10;int n2 = 20;int n3 = 30;Console.WriteLine("参数结果是:{0},{1},{2}", n1, n2, n3);Console.ReadKey();//输出结果为:参数结果是:10,20,30

7、C# 的运算符,和java 不太一样的是它还有其他运算符

运算符描述实例
is判断对象是否为某一类型。If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。
as强制转换,即使转换失败也不会抛出异常。Object obj = new StringReader(“Hello”); StringReader r = obj as StringReader;

8、C# 的访问权限-private、protected、internal、protected internal、public


☺ 9、C# 方法的参数传递,ref关键词的使用,实现参数作为引用类型,out关键字的使用,实现参数作为输出类型

☺ 输出参数的作用:方法没有返回值时,而需要从该方法中返回结果的时候,需要使用输出参数


ref 类型的使用,实现参数作为引用类型:

using System;namespace CalculatorApplication{   class NumberManipulator   {      public void swap(ref int x, ref int y)      {         int temp;         temp = x;          x = y;             y = temp;        }         static void Main(string[] args)      {         NumberManipulator n = new NumberManipulator();                  int a = 100;         int b = 200;         Console.WriteLine("在交换之前,a 的值: {0}", a);         Console.WriteLine("在交换之前,b 的值: {0}", b);                  n.swap(ref a, ref b);//-------这里使用了关键词ref,实现了参数作用引用类型--------         Console.WriteLine("在交换之后,a 的值: {0}", a);         Console.WriteLine("在交换之后,b 的值: {0}", b);          Console.ReadLine();      }   }}

在交换之前,a 的值:100
在交换之前,b 的值:200
在交换之后,a 的值:100
在交换之后,b 的值:200


out关键字的使用,实现参数作为输出类型

using System;namespace CalculatorApplication{   class NumberManipulator   {      public void getValue(out int x )      {         int temp = 5;         x = temp;      }         static void Main(string[] args)      {         NumberManipulator n = new NumberManipulator();                  int a = 100;                  Console.WriteLine("在方法调用之前,a 的值: {0}", a);                           n.getValue(out a);//-------这里使用了关键词out,实现了实现参数作为输出类型--------         Console.WriteLine("在方法调用之后,a 的值: {0}", a);         Console.ReadLine();      }   }}

在方法调用之前,a 的值: 100
在方法调用之后,a 的值: 5



10、不定长参数-关键词 params+数组

public 返回类型 方法名称( params 类型名称[] 数组名称 )
using System;namespace ArrayApplication{   class ParamArray   {      public int AddElements(params int[] arr)  //-----------不定长参数----------      {         int sum = 0;         foreach (int i in arr)         {            sum += i;         }         return sum;      }   }         class TestClass   {      static void Main(string[] args)      {         ParamArray app = new ParamArray();         int sum = app.AddElements(512, 720, 250, 567, 889);         Console.WriteLine("总和是: {0}", sum);         Console.ReadKey();      }   }}



11、可空类型–单问号 ? 与 双问号 ??

■ 可空类型(Nullable Type)表示在值类型的正常取值范围内再加上一个null值.

int i; //默认值0int? ii; //默认值null,可空的int//-----------------------int? i = 3; // 相当于Nullable i = new Nullable(3);

■ 一个?和两个?的区别:

a = b ?? c //b是一个可空的值变量,如果 b 为 null,则 a = c,如果 b 不为 null,则 a = b    double? num1 = null;double num3 = num1 ?? 5.34;      // num1 如果为空值则返回 5.34



12、二维数组的写法有点不同

   static void Main(string[] args)        {                        int[,] a = new int[5, 2] {{0,0}, {1,2}, {2,4}, {3,6}, {4,8} };            int i, j;                        for (i = 0; i < 5; i++)            {                for (j = 0; j < 2; j++)                {                    Console.WriteLine("a[{0},{1}] = {2}", i, j, a[i,j]);                }            }           Console.ReadKey();        }

■ Array 类的常用方法:

Array 类的方法

序号方法 & 描述
1Clear 根据元素的类型,设置数组中某个范围的元素为零、为 false 或者为 null。
2Copy(Array, Array, Int32) 从数组的第一个元素开始复制某个范围的元素到另一个数组的第一个元素位置。长度由一个 32 位整数指定。
3CopyTo(Array, Int32) 从当前的一维数组中复制所有的元素到一个指定的一维数组的指定索引位置。索引由一个 32 位整数指定。
4GetLength 获取一个 32 位整数,该值表示指定维度的数组中的元素总数。
5GetLongLength 获取一个 64 位整数,该值表示指定维度的数组中的元素总数。
6GetLowerBound 获取数组中指定维度的下界。
7GetType 获取当前实例的类型。从对象(Object)继承。
8GetUpperBound 获取数组中指定维度的上界。
9GetValue(Int32) 获取一维数组中指定位置的值。索引由一个 32 位整数指定。
10IndexOf(Array, Object) 搜索指定的对象,返回整个一维数组中第一次出现的索引。
11Reverse(Array) 逆转整个一维数组中元素的顺序。
12SetValue(Object, Int32) 给一维数组中指定位置的元素设置值。索引由一个 32 位整数指定。
13Sort(Array) 使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素。
14ToString 返回一个表示当前对象的字符串。从对象(Object)继承。



13、c# 中还有结构体,在 C# 中的结构与传统的 C 或 C++ 中的结构不同。

■ 在 C# 中的结构与传统的 C 或 C++ 中的结构不同:


■ 类 vs 结构:


■ 举例子:

//声明 Book 结构struct Books{   public string title;   public string author;   public string subject;   public int book_id;};  //使用结构体public class testStructure{   public static void Main(string[] args)   {      Books Book1;                    Book1.title = "C Programming";      Book1.author = "Nuha Ali";      Book1.subject = "C Programming Tutorial";      Book1.book_id = 6495407;            Console.WriteLine( "Book 1 title : {0}", Book1.title);      Console.WriteLine("Book 1 author : {0}", Book1.author);      Console.WriteLine("Book 1 subject : {0}", Book1.subject);      Console.WriteLine("Book 1 book_id :{0}", Book1.book_id);   }}

■ 类 vs 结构的使用场景:

结构和类的区别:

  • 1、结构是值类型,它在栈中分配空间;而类是引用类型,它在堆中分配空间,栈中保存的只是引用。
  • 2、结构类型直接存储成员数据,让其他类的数据位于堆中,位于栈中的变量保存的是指向堆中数据对象的引用。

由于结构是值类型,并且直接存储数据,因此在一个对象的主要成员为数据且数据量不大的情况下,使用结构会带来更好的性能。

因为结构是值类型,因此在为结构分配内存,或者当结构超出了作用域被删除时,性能会非常好,因为他们将内联或者保存在堆栈中。

▷ 结构和类的适用场合分析:



14、c# 的类和java是一模一样的,就是多了个析构函数

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
对象已删除




15、C# 的继承、实现,还有抽象类,重写抽象类的方法的写法以及 abstract 和 virtual 的区别(最后总结一下,在C#中子类和父类的同名方法的关系)

■ 继承语法:

<访问修饰符> class <基类>{ ...}class <派生类> : <基类>{ ...}
 class 子类: 父类
public 子类(参数列表): base(参数列表){}
子类声明的方法{base.父类声明的方法(参数列表);}

■ 举例子:
using System;namespace InheritanceApplication{   class Shape   {      public void setWidth(int w)      {         width = w;      }      public void setHeight(int h)      {         height = h;      }      protected int width;      protected int height;   }   // 派生类   class Rectangle: Shape   {      public int getArea()      {         return (width * height);      }   }   }

■ 接口interface实现的语法:

//声明为接口,使用的关键词还是 interface    // 接口 PaintCost   public interface PaintCost   {      int getCost(int area);//接口中的方法,是没有任何修饰符   }//子类实现接口,是使用冒号,代替java的implements // 派生类   class Rectangle : PaintCost   {      public int getCost(int area)      {         return area * 70;      }   }

▷ 接口:接口是可以有属性看,但是不能有字段的!

// 接口 PaintCostpublic interface PaintCost{ int Cost{set; get;}//接口可以有属性(属性是特殊的方法,属性的特点:是通过set设置值,通过get获取值) //public int cost2; 接口是不能有字段的}
  • 这一块属性的写法,属于简写,详细的介绍,在后边~

▷ 子类实现接口:有两种方式,常用的是隐式(子类实现接口中声明的方法时用 public),显示就是方法前有接口名:

  • 接口interface实现的语法的例子就是隐式实现
// 显示实现,举例子:   // 接口 PaintCostpublic interface PaintCost{      int getCost(int area);//接口中的方法,是没有任何修饰符} // 派生类class Rectangle: PaintCost{      int PaintCost.getCost(int area)      {         return area * 70;      }}

■ 子类继承抽象类,重写抽象类的方法的写法:重写abstract修饰的方法,要加override

abstract class Shape{   abstract public int area();}class Rectangle:  Shape, PaintCost {      public override int area ()      {         Console.WriteLine("Rectangle 类的面积:");         return 100;      }}

■ abstract 和 virtual 的区别:

▷ 区别点:
▷ 举例子:
//abstractabstract class BaseTest1{    public abstract void fun();}class DeriveTest1: BaseTest2{    public override void fun() { }//对于子类继承了抽象类,就必须重写人家所有的抽象方法!}//virtualclass BaseTest2{   public virtual void fun() { }//必须有实现}class DeriveTest2: BaseTest1{    //public override void fun() { } //对于子类继承了父类,可以重写或者不重写 父类 virtual 声明的方法。}

☺ 最后总结,在C#中子类和父类的同名方法的关系,C# 细分了,重写和覆盖是不同的,这里和java 不一样,在java中重写就是覆盖,覆盖就是重写!

▷重写使用的频率比较高,实现多态;覆盖用的频率比较低,用于对以前无法修改的类进行继承的时候。

☺ (1) 重写(关键词是override)

//代码中的写法,多态的写法:父亲 p = new 子类(); //接着调用同名方法p.sameFunction();//这时候,如果子类中和父类的同名方法,没有使用关键词override 进行修饰,那么实际上调用的是父类的方法-------------------------------------------------- 举例子-----------------------------------------------using System;namespace TestApplication{    public class Shape    {        public void ordinaryFunction()        {            Console.WriteLine(" Shape中的ordinaryFunction");        }    }    public class Rectangle: Shape    {        public new void ordinaryFunction()//子类中和父类的同名方法,没有使用关键词override 进行修饰,即没有重写的作用        {            Console.WriteLine(" Rectangle中的ordinaryFunction");        }    }    class RectangleTester    {        static void Main(string[] args)        {            Shape s = new Rectangle();//Rectangle 没有重写的情况下,调用的是父类的方法            s.ordinaryFunction();            Console.ReadKey();        }    }}   

(2) 覆盖(关键词是new)

public class Shape{    public void ordinaryFunction()    {          Console.WriteLine(" Shape中的ordinaryFunction");    }}public class Rectangle : Shape{     public new void ordinaryFunction() //重写基类的同名方法要加上new,否则会有警告     {          Console.WriteLine(" Rectangle中的ordinaryFunction");     }}



☺ 16、总结 c#的重要的关键词 new、virtual、override、abstract、interface

参考:作者-北盟网校,B站视频《https://www.bilibili.com/video/BV1xP4y1y783/》,下面的文字内容就是作者-北盟网校整个视频所讲的重点了~

■ new关键字,目的是为了隐藏父类同名同参数的方法。不写也可以,但会有警告,建议写一下。

■ virtual方法和普通方法一样,但是加上 virtual 后就允许子类重写 override。

■ override目的就是为了多态。

■ abstract方法是抽象方法,没有方法体,抽象方法必须存在抽象类里。

■ interface接口可以有属性。但是不能有字段。方法也是没有修饰符的。没有方法体。



17、C# 命名空间 namespace

C++和C# 提供了namespace的概念来支持这种方式。你可以在全局的空间内指定自己的namespace,然后还可以在某个namespace内制定更小范围的namespace。



18、预处理

C# 预处理器指令列表

预处理器指令描述
#define它用于定义一系列成为符号的字符。
#undef它用于取消定义符号。
#if它用于测试符号是否为真。
#else它用于创建复合条件指令,与 #if 一起使用。
#elif它用于创建复合条件指令。
#endif指定一个条件指令的结束。
#line它可以让您修改编译器的行数以及(可选地)输出错误和警告的文件名。
#error它允许从代码的指定位置生成一个错误。
#warning它允许从代码的指定位置生成一级警告。
#region它可以让您在使用 Visual Studio Code Editor 的大纲特性时,指定一个可展开或折叠的代码块。
#endregion它标识着 #region 块的结束。

预处理器指令指导编译器在实际编译开始之前对信息进行预处理。

所有的预处理器指令都是以 # 开始。且在一行上,只有空白字符可以出现在预处理器指令之前。预处理器指令不是语句,所以它们不以分号(;)结束。

C# 编译器没有一个单独的预处理器,但是,指令被处理时就像是有一个单独的预处理器一样。在 C# 中,预处理器指令用于在条件编译中起作用。与 C 和 C++ 不同的是,它们不是用来创建宏。一个预处理器指令必须是该行上的唯一指令。



19、C# 正则表达式



20、异常

C# 中的异常类主要是直接或间接地派生于 System.Exception 类。System.ApplicationExceptionSystem.SystemException 类是派生于 System.Exception 类的异常类。

  • System.ApplicationException 类支持由应用程序生成的异常。所以程序员定义的异常都应派生自该类。

  • System.SystemException 类是所有预定义的系统异常的基类。



21、反射结合了特性一起使用

(1) 优缺点:

优点:
缺点:

(2) 特性

预定义特性(Attribute)

Net 框架提供了三种预定义特性:

AttributeUsage

▪ 预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。

▪ 规定该特性的语法如下:

[AttributeUsage(   validon,   AllowMultiple=allowmultiple,   Inherited=inherited)]
[AttributeUsage(AttributeTargets.Class |AttributeTargets.Constructor |AttributeTargets.Field |AttributeTargets.Method |AttributeTargets.Property, AllowMultiple = true)]



22、访问器

get 访问器、set 访问器

// 声明类型为 string 的 Name 属性public string Name{   get   {     return name;   }   set   {     name = value;   }}// 简写为:public string Name {get; set;}

using System;namespace runoob{   public abstract class Person   {      public abstract string Name{get; set;}      public abstract int Age{get; set;}   }   class Student : Person   {      private string name = "N.A";      private int age = 0;      // 声明类型为 string 的 Name 属性      public override string Name      {         get         {            return name;         }         set         {            name = value;         }      }      // 声明类型为 int 的 Age 属性      public override int Age      {         get         {            return age;         }         set         {            age = value;         }      }      public override string ToString()      {         return Name = " + Name + ", Age = " + Age;      }   }}



23、委托,关键词 delegate

其实底层就是使用的是反射!

■ 委托:类似于 C 或 C++ 中函数的指针!即用变量调方法。好处:使方法的使用变得更加灵活。

■ 委托在实际使用中的例子:

■ 举例子:

public|internal delegate 返回值 委托名(参数列表);
//声明为委托类型delegate int NumberChanger(int n);--------------------------------------------------------------------  public static int AddNum(int p)  {      num += p;      return num;  }--------------------------------------------------------------------// 使用new 创建委托实例 或者直接使用变量指向方法NumberChanger nc1 = new NumberChanger(AddNum);//相当于 NumberChanger nc1 = AddNum;// 使用委托对象调用方法,执行AddNum 方法nc1(25);

■ 委托的多播,简单理解,理解成java中的链式调用即可

using System;delegate int NumberChanger(int n);namespace DelegateAppl{   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 nc;         NumberChanger nc1 = new NumberChanger(AddNum);         NumberChanger nc2 = new NumberChanger(MultNum);         nc = nc1;         nc += nc2;         // 调用多播         nc(5);         Console.WriteLine("Value of Num: {0}", getNum());         Console.ReadKey();      }   }}

Value of Num: 75



24、事件【设计模式-发布订阅模式】

(1) 为什么需要事件?

看看前面的委托的声明的语法,声明为委托类型的时候,修饰符是 public|internal

而有时候,程序为了安全考虑,需要私有化,即封装起来,不给外界随意调用,随意修改!

委托链可以累加方法,+= 误用了 = 那么只会执行最后一个=的方法,不安全,有被覆盖的隐患

事件实际上是一个私有委托变量,对外界开放了一个向委托变量增加方法绑定的方法,和开放了一个减少委托变量身上绑定的方法


☺ 官网对事件的概述:

事件是一种特殊的多播委托,仅可以从声明事件的类(或派生类)或结构发布服务器类中对其进行调用

如果其他类或结构订阅该事件,则在发布服务器类引发该事件时,将调用其事件处理程序方法

event 关键字用于声明发布服务器类中的事件。

//关于如何声明和引发使用 [EventHandler] 作为基础委托类型的事件public class SampleEventArgs{    public SampleEventArgs(string text) { Text = text; }    public string Text { get; } // readonly}public class Publisher{    // Declare the delegate (if using non-generic pattern).    public delegate void SampleEventHandler(object sender, SampleEventArgs e);    // Declare the event.    public event SampleEventHandler SampleEvent;    // Wrap the event in a protected virtual method    // to enable derived classes to raise the event.    protected virtual void RaiseSampleEvent()    {        // Raise the event in a thread-safe manner using the ?. operator.        SampleEvent?.Invoke(this, new SampleEventArgs("Hello"));    }}
using System;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            Counter c = new Counter(new Random().Next(10));            c.ThresholdReached += c_ThresholdReached;//真实的事件处理方法            for(int i = 0; i < 10; i++)            {                Console.WriteLine("adding one");                c.Add(1);            }        }                static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)        {            Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold,  e.TimeReached);            Environment.Exit(0);        }    }       public class ThresholdReachedEventArgs : EventArgs    {        public int Threshold { get; set; }        public DateTime TimeReached { get; set; }    }        class Counter    {        //声明事件        public event EventHandler ThresholdReached;                private int threshold;        private int total;        public Counter(int passedThreshold)        {            threshold = passedThreshold;        }        public void Add(int x)        {            total += x;            if (total >= threshold)            {                ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();                args.Threshold = threshold;                args.TimeReached = DateTime.Now;                OnThresholdReached(args);//监听或通知事件            }        }             protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)        {            EventHandler handler = ThresholdReached;            if (handler != null)            {                handler(this, e);//事件处理程序            }        }    }}

(2) 事件的本质

以日志事件为例,日志事件写法:public event EventHandler LogHandler; 它的的本质如下:

private delegate EventHandler LogHandler;    public event EventHandler LogHandler{    add    {        LogHandler += value;//添加到事件的方法队列中     }     remove     {         LogHandler -= value;     }}

(3) 事件具有以下属性:



25、C# 不安全代码

当一个代码块使用 unsafe 修饰符标记时,C# 允许在函数中使用指针变量。不安全代码或非托管代码是指使用了指针变量的代码块。




如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

来源地址:https://blog.csdn.net/weixin_45630258/article/details/130051245

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯