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实现反射的效率更高,但是这只适用于简单的反射,更复杂的反射还需要上面的方法处理。


        

原文地址:https://www.cnblogs.com/Abel-Zhang/p/BaseOfLanguage.html