C#学习(4)-----操作符

运算符中一些简单的其实跟C语言差不多,但是还是很有C#特色的。
下列C#所有运算符:

操作符其实有时候不仅仅有单一的意义。操作符是什么意思取决于他操作的变量类型。如下面代码中:

        static void Main()
        {
            string str1 = Console.ReadLine();
            string str2 = Console.ReadLine();
            Console.WriteLine(str1+str2);
        }


操作符+在此处意思是连接两个字符串。

操作符其实也可以自己定义,这取决与你所需要操作的变量是什么。下面我们来看看具体如何自定义操作符。

namespace ConsoleAppPractice
{
    class Program
    {

        static void Main()
        {
            Person papa = new Person();
            Person mom = new Person();
            papa.Name = "Jack";
            mom.Name = "Rose";
            List<Person> nation = Person.GetMarry(papa, mom);
            foreach(var p in nation)
            {
                Console.WriteLine(p.Name );
            }
        }
        
    }
    class Person
    {
        public string Name;
        public static List <Person> GetMarry(Person p1,Person p2)
        {
            //list是一个泛类,只能与尖括号中的其他类构成一个完整的类
            List<Person> people = new List<Person>();
            people.Add(p1);
            people.Add(p2);
            for (int i = 0; i < 11; i++)
            {
                Person child = new Person();
                child.Name = p1.Name + "&" + p2.Name + "'s child";
                people.Add(child);
            }
            return people;
        }
    }
}

以上所隐含的加法运算,意义是将两个人marry形成11个孩子。因而此处我们可以引入类加法定义:

public static List <Person>operator +(Person p1,Person p2)

List<Person> nation = papa + mom;

只需改变这两行代码即可。

由此可以明确,其实操作符本质上还是函数,有特定需要的参数类型和功能。使用操作符是简化了书写。

注:

关于此处operator后面所跟着的那个符号,我试了一下,可能因为这个是二元的吧,似乎只有+、-、/、%、^、*可用。

其中有一个很有意思的点就是,如果要定义一个新的小于<,系统会要求你也要同时定义一个大于>。

如果使用!=和==,系统会报warning: 'Person' defines operator == or operator != but does not override Object.GetHashCode()    看来运算符也有覆盖这一说,可以联想到等会会写到的子类与父类。

再者,这样的操作符重载必须写在要定义的类里,如例子中只能写在Person类不能写在program类不然会报错“One of the parameters of a binary operator must be the containing type”。血淋淋的教训www

一、基本运算符
1、x.y成员访问操作符
也成为点操作符,可以用来访问外层名称空间中的子集名称空间,还可以访问名称空间内的类型,还可以访问类型的静态成员,还可以访问对象成员。总之哪里有成员哪里有他。

2、[]操作符

访问集合中的元素,比如说数组和字典。

在C#中,声明数组的方法是在数据类型后面加[]。如:

int[] a = new int[5] { 1, 2, 3, 4, 5 };
//可在后面加上{}来初始化数组。默认为0.

A[] a = new A[2] { new A(), new A() };
//对象集合需要每个元素都进行一次引用初始化

Form myForm = new Form(){Text = "Hello"};
//{}这个符号是初始化器喔

下面我们来看看访问字典的方式。

namespace ConsoleAppPractice
{
    class Program
    {

        static void Main()
        {
            Dictionary<string, Student> stuDic = new Dictionary<string, Student>();
            for (int i = 0; i <=100; i++)
            {
                Student stu = new Student();
                stu.name = "s_" + i.ToString();
                stu.score = 100;
                stuDic.Add(stu.name, stu);
            }
            Student number6 = stuDic["s_6"];
            Console.WriteLine(number6 .score );
        }
        
    }
    class Student
    {
        public int score;
        public string name;
    }
    
}

Dictionary是一个泛类。它尖括号中第一个参数是索引,即你需要通过这个来查找某个元素。第二个参数自然就是字典里面的元素的数据类型。

注:自创建索引:

差不多是属性格式。

        public int[] this [int index]
        {
            get
            {
                return this.values[index];
            }
        }

3.typeof

static void Main()
        {
            Type t = typeof(int);
            Console.WriteLine(t.Name );
            Console.WriteLine(t.AssemblyQualifiedName );
            Console.WriteLine(t.Namespace );
            int c = t.GetMethods().Length;
            foreach (var mi in t.GetMethods())
            {
                Console.WriteLine(mi.Name );
            }
            Console.WriteLine(c);
        }

使用typeof来看一个数据类型的相关操作。

namespace ConsoleAppPractice
{
    class Program
    {

        static void Main()
        {
            Type c = typeof(person);
            Console.WriteLine(c.GetMethods ().Length );
            Console.WriteLine(c.Name);
            Console.WriteLine(c.FullName );
            foreach (var mi in c.GetMethods())
            {
                Console.WriteLine(mi.Name );
            }
        }
        
    }
    class person
    {
        public double Add(double a,int b)
        {
            return a + b;
        }
        public static int Add(int a,int b)
        {
            return a + b;
        }
        double Add(int a, double  b)
        {
            return a + b;
        }
    }
    
}
//运行结果:

/*
6
person
ConsoleAppPractice.person
Add
Add
Equals
GetHashCode
GetType
ToString
*/

自定义的类,里面不public的方法就不会计算在typeof所包含的方法里。

4、default

功能是获取一个类型的默认值

int x = default(int);

当default发现为结构体时返回0;如果是枚举类型,返回枚举类型里面对应为0的那个东西;如果是类,返回null。

用default获取枚举值时要小心,在设计枚举类型时也要记得搞出一个0。

5、new操作符

首先介绍一下var这个关键字,之前文章就有提到过,它可以帮助我们生成隐式类型的变量。

接着说new。new的用处还蛮多的。作为操作符,new可以在内存中构建一个实例,并且立即调用实例构造器,再将地址穿给引用变量,构造了一个桥梁。

new操作符还能调用{}初始化器:

int[] a = new int[5] { 1, 2, 3, 4, 5 };

A[] a = new A[2] { new A(), new A() };

Form myForm = new Form(){Text = "Hello"};

但注意不是所有的类创建实例都需要new操作符,比如说string就不需要。是微软为了统一基本操作类型的体验才对string进行了简化。这一过程叫作语法糖衣。{很形象!}其实数组也有这个现象发生。你可以直接int[] a = {1,2,3,4,5};

new有一个非常重要的用途,就是对匿名类型的创建。

var person = new { Name = "Mr.Okay", Age = 32 };

如果这时候对person变量进行gettype操作,会得到如下type:

<>表示这个类型是泛类型,‘2表示构成这个类型需要两个其他的类型。

由着我们才可以发现var与new这个组合技的强大之处。平时我们写代码也可以在设对象时偷懒写var,这是被鼓励的一个方式。

但事实上,功能越强大,new操作符就越危险。因为new操作符事实上紧紧耦合了main所在这个类与调用的类,使得类间的依赖关系增强。如果是大程序,我们常用依赖注入的方法将其变成松耦合。

其实new这个关键字还有很多别的用处。比如说,除了作为操作符,它还可以作为函数的修饰符。例如以下代码:

class Program
    {
        
        static void Main()
        {
            
            //派生类会自动继承其父类里面所有的内容
            Student stu = new Student();
            stu.haha();
            CsStudent csStu=new CsStudent();
            csStu.haha();
        }

    }

    class Student
    {
        public void haha()
        {
            Console.WriteLine("hello!");
        }
        
    }
    //类与类之间有种关系叫继承(也叫做派生)
    class CsStudent : Student
    {
        new public void haha()//除了有new外其他都与父类相同
        {
            Console.WriteLine(" world!");
            //new操作符会覆盖掉从父类继承来的函数
            //子类对父类的方法进行隐藏
        }
    }

我们使用了:来声明一个派生的类,这个类继承了其父类(:右边那个类)的所有内容。

但是如果此时在子类里使用new操作符,就会发生子类对父类的隐藏。

6、checked和unchecked

用来检验数值溢出、数组越界等等功能(似乎不能检查栈溢出)

如果检测到错误,将错误打在屏幕上,并终止运行程序。

使用checked有两种方法:

//方法1:
static void Main()
        {
            int x = int.MaxValue;
            checked
            {
                x++;
            }
        }

//方法2:
static void Main()
        {
            int x = int.MaxValue;
            int y = checked(x + 1);
        }

我们一般与try-catch语句结合:

static void Main()
        {
            try
            {
                checked
                {
                    int x = int.MaxValue;
                    x++;
                }
            }
            catch (OverflowException us)
            {
                Console.WriteLine("error!");
                throw;
            }
        }

catch语句里面的那个throw的有无还是有点区别的。

7.delegate

其实他作为委托类型更广泛,现在很少用来操作符了。landa表达式把他取代了。

他主要用来声明一个匿名的方法。

8、sizeof

sizeof用以获取基本数据类型中的结构体【就是那些关键字啦】所占的字节数。当然除了string和object。因为他们是类。

如果想获取自定义的结构体的字节数,需要将其放在不安全的上下文。跟C语言一样,此处结构体内存计算也存在内存对齐现象。如结构体中一个int一个long,最后得到结果是16而不是12。

9.->

在C语言中是指针访问成员的操作符。

在C#中必须在不安全的情况下使用,并且C#语言严格规定,取地址操作和指针操作只能用在结构体。

二、一元操作符

1.-

我们得到负数的方式,是写出数字的原码,然后除了符号位,按位取反再加一。

在计算机内部,将一个负数变成他的绝对值,是在补码基础上,包括符号位按位取反再加一。

2.!

可用于安全性的检验。

namespace ConsoleAppPractice
{
    class Program
    {

        static void Main()
        {
            var a = new Student("zz");
            Console.WriteLine(a.name );
        }
        
    }
    class Student
    {
        public string name;
        public Student(string ininame)
        {
            if (!string.IsNullOrEmpty(ininame ))
            {
                this.name = ininame;
            }
            else
            {
                throw new ArgumentException("error!");
            }
        }
    }
    
}

3、(T)x

这是强制类型转换。这货很重要,下期再接着讲。

4.*/%

与操作变量有关,跟C语言差不多,不多作赘述。

注意一下NAN=∞*0=x/0

∞:infinity

还有C#中浮点数之间也是可以取余的。

        static void Main()
        {
            double x = 3.5;
            double y = 3;
            Console.WriteLine(x%y);
        }
//运行结果:0.5

5.>>与<<

在不溢出的情况下,左移就是乘2,右移就是除2.

右移,如果是正数,最高位补0,负数补1.

6.逻辑运算符

C#支持浮点数与整型的比较。

string类型只能比较是否相等。如果要忽略大小写:

先全部转为小写再比较。

        static void Main()
        {
            string str1 = "Abc";
            string str2 = "abc";
            Console.WriteLine(str1.ToLower ()==str2.ToLower());
        }

三、其他

1.is

用于检测一个变量牵着的实例是否是某个类型,返回布尔值

namespace ConsoleAppPractice
{
    class Program
    {
        static void Main()
        {
            haha ha = new haha();
            var c = ha is Program;//注意is的左边操作对象是实例不能是类
            Console.WriteLine(c.GetType().Name);
            Console.WriteLine(c);
        }

    }

    class haha : Program
    {
        public static int a = 0;
    }

}
//输出结果:Boolean  True
        static void Main()
        {
            haha ha = null;
            var c = ha is Program;
            Console.WriteLine(c);
        }
//输出结果:False

其实感觉is也可以用于数比较哪,还可以用于检测是否为空。

        static void Main()
        {
            int x = 2;
            Console.WriteLine(x is 2);
        }
//运行结果:True

2.as

有点C语言三元操作符?那味了。

下段代码意思是,o牵着的实例是不是haha类型的?是的话,将o的对象的地址交给t,不是的话传NULL值。

        static void Main()
        {
            haha o = new haha();
            o.a = 2;
            haha t = o as haha;
            Console.WriteLine(t.a);
        }
//输出结果:2

注意:此处如果将o作为object,是不可以调用haha这个类里面的东西的,因为当你试图用引用变量来访问实例内容的时候,只能访问这个引用变量的类型所具有的成员。

3.?可空操作符

null只能赋值给引用变量,不能赋值给值变量。

但是你如果非要,有两种方法。
一是使用泛类型:

        static void Main()
        {
            Nullable<int> x = null;
        }


二就是使用可空操作符?
因为可空类型常用,故而已经被吸收成关键字惹。

        static void Main()
        {
            int? x = null;
            Console.WriteLine(x is null);
        }
//运行结果:True

这三个类型似乎是int?所特有的。第一个是看有没有值,返回True或False.

第二个是看什么值,如果为空程序崩溃。

第三个是看有没有值和值是什么,有值则返回值,没有返回0.

string类型的空值可以:

string str = string.Empty;

4.null合并操作符??

x是空吗?是的话,0赋值给y,x保持不变。

        static void Main()
        {
            int? x = null;
            int y = x ?? 0;
            Console.WriteLine(x);
            Console.WriteLine(y);
        }
//输出结果:  (空)0

5.条件操作符?:

下面两段代码是等价的

        static void Main()
        {
            string str = string.Empty;
            string x = Console.ReadLine();
            int score = Convert.ToInt32(x);
            if (score >= 60)
            {
                str = "Pass";
            }
            else
            {
                str = "Failed";
            }
            Console.WriteLine(str);
        }
        static void Main()
        {
            string x = Console.ReadLine();
            int score = Convert.ToInt32(x);
            string str = (score >= 60) ? "Pass" : "Failed";
            Console.WriteLine(str);
        }
//score大于60吗?是的话,返回pass;不是的话,返回failed。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值