• C#基础笔记——语言基础


    一、概述:

    C#基础我想每一个.NET程序猿都学习过,但是如何使用才是最优方法呢?往往这些基础知识被大家忽略。

    怎样操作字符串?如何进行类型转换?什么是克隆?为什么需要HashCode?

    今天我们就来系统的回顾一下基础知识。

    二、实现:

    1. 字符串拼接

    下面我们看一下下面代码:

    string a = "t";
    string b = "e";
    string c = "s";
    //方法1
    string result = a + b + c;
    //方法2
    StringBuilder strBuilder = new StringBuilder();
    strBuilder.Append(a);
    strBuilder.Append(b);
    strBuilder.Append(c);
    string resultBuilder = strBuilder.ToString();
    //方法3,
    string.Format("{0}{1}{2}", a, b, c);

      方法1,对字符串进行进行“=”或者“+”操作时,内存都会创建一个新的字符串对象并且分配新的空间。

      方法2,StringBuilder不会重新创建一个string对象,而是以托管的方式分配内存

      方法3,推选,Format内部使用StringBuilder实现的,但是操作更灵活清晰。

    2. 使用默认类型转换

    下面我们介绍一下Parse和TryParse哪个更实用

                string str = string.Empty;
                string str1 = "123";
                double d = 0D;
                long ticks;
                Stopwatch sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000; i++)
                {
                    try
                    {
                        d = Double.Parse(str1);
                    }
                    catch
                    {
    
                        d = 0;
                    }
                }
                sw.Stop();
                ticks = sw.ElapsedTicks;
                Console.WriteLine("Parse()耗时:{0},执行结果:{1}", ticks, d);
                //这样做是安全的,但是结构太繁琐,让我们试试
                  sw = Stopwatch.StartNew();
                for (int i = 0; i < 1000; i++)
                {
                    if (!Double.TryParse(str1, out d))
                    {
                        d = 0;
                    }
                }
                sw.Stop();
                ticks = sw.ElapsedTicks;
                Console.WriteLine("TryParse耗时:{0},执行结果:{1}", ticks, d);

    输出结果:

      Parse()耗时:32553653,执行结果:0

      TryParse()耗时:638,执行结果:0

    3. 区别对待强制转型与as和is

    我们有两个类,

      class FirstType
        {
            public string Name { get; set; }
        }
    
      class SecondType : FirstType
        { }

    如何进行类型转换:

      SecondType secondType = new SecondType() { Name = "Abel" };
      FirstType firstType1 = (FirstType)secondType;
      FirstType firstType2 = secondType as FirstType;

    很明显As更可读。

    4.使用int?确保值类型也可以为null

    数据存储中数据库所有变量的初始值都可以为null,包括基类型int,我们在程序中如何实现呢?

                int? num = null;
                int cons = 0;
                num = cons;
                Console.WriteLine("int? num 被成功赋值:{0}", num);
                //反过来
              int? consnum = 1234;
                int number;
                if (consnum.HasValue)
                {
                    number = consnum.Value;
                }
                else
                {
                    number = 0;
                }
                //number = consnum ?? 0;
                Console.WriteLine("number被成功赋值:{0}", number);
    

    代码中备注掉的部分(number = consnum ?? 0)与上面的if实现功能一样,但更简洁。

    与双目运算符(?:)差不多,consnum.HasValue为true则将consnum.Value值赋给number,否则number的值为0

    5.区分readonly与const的使用方法

    const是一个变异期的常量,readonly是运行期的常量

    const至修饰基元类型,枚举,字符串类型,readonly没有限制。

    const是编译型常量所以它天然就是static的,不能手动再为const添加static修饰。

    readonly的全部意义在于运行第一次赋值后将不会改变。当然不可改变分两层意思:对于基类型变量本身不能改变,对于引用类型本身指针不可改变。

    6.运算符重载:

    我们实现对象相加重载

    class OperatorSalary
        {
            public float RMB { get; set; }
            public static OperatorSalary operator +(OperatorSalary s1, OperatorSalary s2)
            {
                s1.RMB += s2.RMB;
                return s1;
            }
        }

    调用代码:

    OperatorSalary mikeincom = new OperatorSalary() { RMB = 22 };
    OperatorSalary roseincom = new OperatorSalary() { RMB = 33 };
    OperatorSalary allincom = mikeincom + roseincom;
    Console.WriteLine("工资和为: {0}", allincom.RMB);

    这样我们实现对象相加重载,基本运算重载都是类似的。

    7.对象比较器:

    对象比较器重写需要继承接口IComparable<T>和IComparer<T>

        class Salary : IComparable<Salary>
        {
            public string Name { get; set; }
            public float BaseSalary { get; set; }
            public float Bonus { get; set; }
    
            public int CompareTo(Salary other)
            {
                return this.BaseSalary.CompareTo(other.BaseSalary);
            }
        }
    
        class BonusComparer : IComparer<Salary>
        {
            public int Compare(Salary x, Salary y)
            {
                return x.Bonus.CompareTo(y.Bonus);
            }
        }

    实现代码如下:

                List<Salary> CompanySalary = new List<Salary>(){
                new Salary{Name="Abel",BaseSalary=20000.10f,Bonus=1000f},
                new Salary{Name="Tomson",BaseSalary=40000.10f,Bonus=2000f},
                new Salary{Name="Lucy",BaseSalary=30000.10f,Bonus=4000f},
                new Salary{Name="Erwin",BaseSalary=60000.10f,Bonus=5000f},
                new Salary{Name="Steven",BaseSalary=80000.10f,Bonus=3000f}
                };
                //首先我们以基本工资排序
                CompanySalary.Sort();
                foreach (Salary item in CompanySalary)
                {
                    Console.WriteLine(string.Format("Name:{0} 	 Basesalary:{1} 	 Bonus:{2}",item.Name,item.BaseSalary,item.Bonus));
                }
                //然后我们以奖金排序
                CompanySalary.Sort(new BonusComparer());
                foreach (Salary item in CompanySalary)
                {
                    Console.WriteLine(string.Format("Name:{0} 	 Basesalary:{1} 	 Bonus:{2}", item.Name, item.BaseSalary, item.Bonus));
                }

    8.区别对待==和Equals

    重写Equals时也需要重写GetHashCode这需要继承IEquatable<T>泛型接口

        class PersonMoreInfo
        {
            public string SomeInfo { get; set; }
        }
        class Person:IEquatable<Person>
        {
            public string IDcode { get; private set; }
            public string Name { get; set; }        
             
            public Person(string idcode)
            {
                this.IDcode = idcode;
            }
            public override bool Equals(object obj)
            {
                return this.IDcode==(obj as Person).IDcode;
            }
            public  bool Equals(Person otherPerson)
            {
                return this.IDcode == otherPerson.IDcode;
            }
            public override int GetHashCode()
            {
              //return this.IDcode.GetHashCode();// 它永远返回一个整型类型,而整型显然无法满足字符串的容量,这是可能返回相同的Hashcode。
                //下面写法避免HashCode重复:
                return (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + this.IDcode).GetHashCode();
            }
        }

    实现代码:

        Dictionary<Person, PersonMoreInfo> PersonValue = new Dictionary<Person, PersonMoreInfo>();
        PersonMoreInfo abelValue = new PersonMoreInfo() { SomeInfo = "Mike's info" };
        Person Abel = new Person("NB0903100006");
        Person Erwin = new Person("NB0903100006");
        PersonValue.Add(Abel, abelValue);
        Console.WriteLine("Abel的HashCode:",Abel.GetHashCode());
        Console.WriteLine(string.Format("Abel和Erwin{0}", Abel.Equals(Erwin) ? "相等" : "不相等"));
        Console.WriteLine(string.Format("Abel和Erwin{0}", PersonValue.ContainsKey(Erwin) ? "相等" : "不相等"));

    9.格式化字符串

    重写ToString()方法需要继承IFormatttable接口

        class People : IFormattable
        {
            public string IDCode { get; set; }
            public Name Name { get; set; }
            //实现接口IFormattable的ToString
            public string ToString(string nameType, IFormatProvider formatProvider)
            {
                NameWord peopleNameToString = new NameWord();
                var method=typeof(NameWord).GetMethod(nameType);
                object obj=new object();
                obj = this;
                return method.Invoke(peopleNameToString, new object[] { obj }).ToString();
            }  
        }
    
        class Name
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
        class NameWord
        {
            public string chineseName(People people)
            { return string.Format("中文名字:{0}", people.Name.FirstName); }
    
            public string englishName(People people)
            { return string.Format("英文名字:{0}.{1}", people.Name.FirstName,people.Name.LastName); }
    
            public string japaneseName(People people)
            { return string.Format("日语名字:{0}.{1}", people.Name.FirstName, people.Name.LastName); }
    
            public string franceName(People people)
            { return string.Format("法语名字:{0}.{1}", people.Name.FirstName, people.Name.LastName); }
    
            public string elseName(People people)
            { return this.ToString(); }
        }

    代码实现:

    People abelzhang = new People() { IDCode = "123", Name = new Name() { FirstName="zhang",LastName="Abel"} };
    Console.WriteLine(abelzhang.ToString("chineseName", null));

    这里本想用反射和表驱动法代替Switch,但是重写ToString方法发参数必须是string类型的,无法使用enum类型。

    希望匠友们给出宝贵意见。

    10.克隆:正确实现前拷贝和深拷贝

        [Serializable]
        class Employee : ICloneable
        {
            public string IDCode { get; set; }
            public int Age { get; set; }
            public Department department { get; set; }
    
            public object Clone()
            {
                return this.MemberwiseClone();
            }
    //用序列化实现深拷贝 public Employee DeepClone() { using(Stream objectStream=new MemoryStream() ) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(objectStream, this); objectStream.Seek(0, SeekOrigin.Begin); return formatter.Deserialize(objectStream) as Employee; } }
    //实现浅拷贝 public Employee ShallowClone() { return Clone() as Employee; } } [Serializable] class Department { public string Name { get; set; }
    public override string ToString() { return this.Name.ToString(); } }

    这里深拷贝用序列化实现的。

        Employee AbelCopy = new Employee() { IDCode = "123", Age = 26, department = new Department() { Name="Abel"} };
        Employee LucyCopy = AbelCopy.ShallowClone();
        Employee ErwinCopy = AbelCopy.DeepClone();
        Console.WriteLine("LucyCopy---ID:{0},Age:{1},Department:{2}", LucyCopy.IDCode, LucyCopy.Age, LucyCopy.department.Name);
        Console.WriteLine("ErwinCopy---ID:{0},Age:{1},Department:{2}", ErwinCopy.IDCode, ErwinCopy.Age, ErwinCopy.department.Name);
        AbelCopy.IDCode = "321";
        AbelCopy.Age = 27;
        AbelCopy.department.Name = "Lucy";
        Console.WriteLine("LucyCopy---ID:{0},Age:{1},Department:{2}", LucyCopy.IDCode, LucyCopy.Age, LucyCopy.department.Name);
        C

    11.简单的反射实现

    我们先有一个普通的类。

     public class DynamicSample
        {
            public string Name { get; set; }
    
            public int Add(int a, int b)
            {
                return a + b;
            }
        }

    实现Add方法的反射

        int times = 1000000;
        DynamicSample reSample = new DynamicSample();
        var addMethod= typeof(DynamicSample).GetMethod("Add");
        Stopwatch WatchDynamic1=Stopwatch.StartNew();
        for (int i = 0; i < times; i++)
        {
            addMethod.Invoke(reSample,new object[]{1,2});
        }
        WatchDynamic1.Stop();
        Console.WriteLine(string.Format("反射耗时:{0}毫秒", WatchDynamic1.ElapsedMilliseconds));
    
        dynamic dySample = new DynamicSample();
        Stopwatch WatchDynamic2 = Stopwatch.StartNew();
        for (int j = 0; j < times; j++)
        {
            dySample.Add(1,2);
        }
        WatchDynamic2.Stop();
        Console.WriteLine(string.Format("dynamic耗时:{0}毫秒", WatchDynamic2.ElapsedMilliseconds));

    输出结果:

    反射耗时:3490毫秒

    dynamic耗时:330毫秒

    从上面的例子分析dynamic实现反射的效率更高,但是这只适用于简单的反射,更复杂的反射还需要上面的方法处理。


            

  • 相关阅读:
    焦虑来回走
    去省政府客串
    中国地质大学(北京)招生信息有点坑
    张桂梅校长再获殊荣,实至名归!她的故事值得一看再看……
    行内容转为列内容
    公文写作心得
    钟南山院士亲口说的“如何保持健康长寿
    VMware虚拟机出现“内部错误”如何解决?
    CI框架深入篇(2)一些基础的我之不知道的标准格式
    SQL语句学习记录(三)
  • 原文地址:https://www.cnblogs.com/Abel-Zhang/p/BaseOfLanguage.html
Copyright © 2020-2023  润新知