c#语法(一)

2018-06-22  本文已影响12人  耳_总

第一个hello world

using System;

namespace MyApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
命名空间 namespace

namespace 相当于java 的包,package。cs 的代码的最小模块是class(类),而类包含在命名空间里面,大括号包裹代码快,里面可以申明类。using xxxx就是使用别的命名空间的代码,相当于java的导包 import.
Console.WriteLine窗口的输出打印。

关键字
字符串操作
static void Main(string[] args)
        {
            string name = "许聪";
            int age = 18;
            Console.WriteLine("my name is {0} and age is {1}",name,age);// 
        }

cs 的占位符以大括号包围,里面为序列号,0,1...代表第几个变量

C# 数据类型

数据类型有三种值类型、引用类型、指针类型

类型 描述 范围 默认值
bool 布尔值 True 或 False False
sbyte 8 位有符号整数类型 -128 到 127 0
uint 32 位无符号整数类型 0 到 4,294,967,295 0
ulong 64 位无符号整数类型 0
ushort 16 位无符号整数类型 0
sbyte 8 位无符号整数类型 0

可以用sizeof(type) 来查看一个数据占几个字节

  1. 内置的 引用类型有:object、dynamic 和 string
  2. Object 也是所有引用类型的基类,也有自动装箱拆箱。
  3. Dynamic动态类型:可以存储任何类型的值在动态数据类型变量中。这些变量的类型检查是在运行时发生的
dynamic d = 20;

动态类型与对象类型相似,但是对象类型变量的类型检查是在编译时发生的,而动态类型变量的类型检查是在运行时发生的

  1. string 类型
    @引号字符串
string d = @"hello \t world";               // hello \t world

引号字符串不考虑转义字符,将转义字符看成普通字符,和kotlin的""" xxxx """ 相似
xx* 指针类型
c/c++ 指针类型一样

类 class

cs 的类的声明和实例化和java几乎一样

类型转换

在c#中,基础数据类型是有和kotlin一样的类型转换函数:
int a = 3;
a.

接收用户的键盘输入
int num;
num = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("num = {0}", num);
循环控制
int[] arr = {1,2,3,4,5 };
            foreach(int item in arr)
            {
                Console.WriteLine("item : {0}",item);
            }
参数传递

在 C# 中,有三种向方法传递参数的方式:
一、值参数:在使用参数时,是把一个值传递给函数使用的一个变量。对函数中此变量的任何修改都不会影响函数调用中指定的参数。(由于函数只有一个返回值,不能用作参数的多个变量值)。

二、引用参数:即函数处理的变量与函数调用中使用的变量相同,而不仅仅是值相同的变量。因此,对这个变量的任何改变都会影响用作参数的变量值。需用ref关键字指定参数。用作ref参数的变量有两个限制,由于函数可能会改变引用参数的值,所有必须在函数调用中使用“非常量”变量。其次,必须使用初始化过的变量。

三、输出参数:out关键字,指定所给定的参数是一个输出参数。Out关键字的使用方式与ref关键字相同,实际上,他的执行方式与引用参数完全一样,因为在函数执行完毕后,该参数的值将返回给函数调用中使用的变量。

四、引用参数和输出参数的一些重要区别:

把未赋值的变量用作ref参数是非法的,但可以把未赋值的变量用作out参数。
另外,在函数使用out参数时,必须把它看成是尚未赋值。即调用代码可以把已赋值的变量用作out参数,但存储在该变量中的值会在函数执行时丢失。

可空类型

定义:

int? i = null;
Nullable<int> ii = new Nullable<int>(2);

可以用个?来声明是一个可空类型,或者Nullable这个特殊类型来定义。
c#的数据类型分为值类型(基础数据类型)和引用类型,引用类型是可以为空的,但是基础数据类型是有默认值的,int i = 0 i的默认值为0,但是数据库中就存在没有定义的情况,有没有默认值,所以为了和数据库的类型对应上就增加了空类型,比如,bool类型就有三个值:true,false,null

            Nullable<int> ii = new Nullable<int>(2);
            Console.WriteLine("i = {0}", i);// i = 
            int j = i ?? 3;
            Console.WriteLine("j = {0}", j);// j =3
C# 结构体

结构体用struct 关键字声明,结构体是值类型数据结构。它使得一个单一变量可以存储各种数据类型的相关数据

struct Book
    {
        public string name;
        public float price;
        public string author;

    }
public static void Main(string[] args)
        {
            Book book;
            book.name = "c入门到放弃";
            book.author = "xucong";
            book.price = 2.3f;
          
        }
C# 中的析构函数

和c++的析构函数类似,在类回收的时候来调用,java 里面也有类似的方法finalize(),在类回收之前调用,但是java里面的这个方法不一定可靠。
析构函数定义为类名前加上“~”后面名字的方法:

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

虚方法、方法的继承重写
  1. java中的方法重写,子类只需要复写父类的方法,在子类的实例的引用调用该方法的时候,调用的是子类的复写的方法:
A a = new B()
a.fun()

其中B是A的子类,fun是B复写A的方法,a.fun()执行的就是子类的方法。
但是在c#中当父类的引用指向子类的引用的时候和java就有较大的差异了。c#里面称为声明类和实例类,上面A称为声明类,B称为实例类。方法的调用遵循下面规则:

当调用一个类的实例的时候,首先会去检查这个类的声明类,检查这个方法是否是virtual方法
如果这个方法不是virtual方法,会调用声明类中的该方法,如果该声明类中找不到就去父类找该方法。

    class A
    {
        public virtual void fun1()
        {
            Console.WriteLine("A:fun1");
        }

        public void fun2()
        {
            Console.WriteLine("A:fun2");
        }
    }

    class B : A
    {
        public override void fun1()
        {
            Console.WriteLine("B:fun1");
        }

        public void fun2()
        {
            Console.WriteLine("B:fun2");
        }
    }

A a = new A();
A b = new B();   
a.fun2();
b.fun2();
// 输出
//A:fun2
//A:fun2

A a = new A();
B b = new B();   
a.fun2();
b.fun2();
// 输出
//A:fun2
//B:fun2

把B类修改为:

class B : A
    {
        public override void fun1()
        {
            Console.WriteLine("B:fun1");
        }
        // 去掉func2方法
    }

A a = new A();
B b = new B();   
a.fun2();
b.fun2();
// 输出
//A:fun2
//A:fun2

这里需要注意:
上面A、B的fun2在java中是重写方法,但是在c#这里不是,子类允许定义和父类相同的方法,如果是重写方法,需要满足两个条件:1、父类的这个方法是overide,2、父类的方法是virtual的。而且如果是方法重写的,则必须有overide 关键字,否则视为普通方法。
普通方法看完了,接下来看virtual方法:

如果执行当前的方法是虚方法,则取实例类里面去找到相应的虚方法,在这个实例类里,他会检查这个实例类的定义中是否有重新实现该虚函数(通过override关键字),如果是有,那么OK,它就不会再找了,而 马上执行该实例类中的这个重新实现的函数。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在实例类里的检查,直到找到第一个重载了 该虚函数的父类为止,然后执行该父类里重载后的函数。

class A
    {
        public virtual void fun1()
        {
            Console.WriteLine("A:fun1");
        }
    }

    class B : A
    {
       
    }

    class C : B
    {
        public override void fun1()
        {
            Console.WriteLine("C:fun1");
        }
    }

A a = new A();
A b = new B();
A c = new C();

a.fun1();
b.fun1();
c.fun1();
输出:
A:fun1
A:fun1
C:fun1
运算符重载

c#可以重载内置运算符,这个语法和c++是一样的,一般我们我们的运算符有加、减、大于、等于,等等,这些都是作用在数字类型的变量上,但是如果需要对一个对象进行这些运算就需要运算符重载了。
定义:

public class Box
    {
        int weight;

        public static MyApp1.Box operator +(Box a,Box b)
        {
            Box box = new Box();
            box.weight = a.weight + b.weight;
            return box;
        }

        public static void Main(string[] args)
        {
            Box a = new Box();
            a.weight = 3;
            Box b = new Box();
            b.weight = 4;
            Console.WriteLine((a + b).weight);
            // 输出:7
        }
    }

运算符重载以关键字operator 后面紧跟运算符定义,参数的个数和类型往往也是有限定的。定义完成之后我们就可以对对象进行和数字类型一样进行加号操作。

委托和事件
匿名方法&lambda表达式

委托代表一类签名相同的函数(相同参数合返回值),匿名函数和lambda表达式也是一样,所以委托可以用匿名函数和lambda表达式来表示,java的lambda表达式表达的是函数式接口,c#的lambda表达的是匿名方法。

不安全代码

c#中可以和c/c++一样用指针操作变量,这样的代码块称之为不安全代码,不安全代码块需要用unsafe关键字包裹起来。
c#对于指针的声明和使用方法和c语言是一样的。

int a = 10;
int* p = &a;
Console.WriteLine("p = {0}", *p);// 10
int[] arr = new int[4]{ 1, 2, 3, 4 };
fixed (int* arr_p = arr)
for (int i = 0; i < 3; i++) {
      Console.WriteLine("i = {0}", *(arr_p + i));                      
}
int* ptr = stackalloc int[3];
协程

https://blog.csdn.net/qq_30695651/article/details/79105332
https://blog.csdn.net/dk_0520/article/details/53859871
https://blog.csdn.net/fjl2007/article/details/46860561
http://dsqiu.iteye.com/blog/2029701
http://gad.qq.com/article/detail/28027
http://www.voidcn.com/article/p-tlctyuiq-bcx.html
http://www.unity.5helpyou.com/2658.html

public class CoroutinesExample : MonoBehaviour
{
    public float smoothing = 1f;
    public Transform target;

    void Start ()
    {
        StartCoroutine(MyCoroutine(target));
    }

    // 注意这个函数返回值是IEnumerator,必须    
    IEnumerator MyCoroutine (Transform target)
    {
        // 处理第一阶段
        // 和目标大于0.05就按照smoothing * Time.deltaTime移动一段距离
        while(Vector3.Distance(transform.position, target.position) > 0.05f)
        {
            transform.position = Vector3.Lerp(transform.position, target.position, smoothing * Time.deltaTime);
            yield return null;// 这里暂停后返回,等待下帧执行机会
        }
        print("我到了");

        // 处理第二阶段
        yield return new WaitForSeconds(3f);
        print("完成!");
    }
}

monobehavior.png

unity中的yield
yield 后面可以跟的表达式:
a) return null - 等下个Update之后恢复
b) return new WaitForEndOfFrame() - 等下个OnGUI之后恢复
c) return new WaitForFixedUpdate() - 等下个FixedUpdate之后恢复,有可能一帧内多次执行
d) return new WaitForSeconds(2) - 2秒后,等下个Update之后恢复
e) return new WWW(url) - Web请求完成了,Update之后恢复
f) return StartCorourtine() - 新的协成完成了,Update之后恢复
g) break -退出协程
h) return Application.LoadLevelAsync(levelName) - load level 完成,异步加载场景
i) return Resources.UnloadUnusedAssets(); // unload 完成

/// <summary>
    /// 延时执行
    /// </summary>
    /// <param name="action">执行的委托</param>
    /// <param name="delaySeconds">延时等待的秒数</param>
    public IEnumerator DelayToInvokeDo(Action action, float delaySeconds)
    {
        yield return new WaitForSeconds(delaySeconds);
        action();
    }
    /// <summary>
    /// 使用例子
    /// </summary>
     StartCoroutine(DelayToInvokeDo(delegate() {
                task.SetActive(true);
                task.transform.position = Vector3.zero;
                task.transform.rotation = Quaternion.Euler(Vector3.zero);
                task.doSomethings();
            },1.5f));

上一篇下一篇

猜你喜欢

热点阅读