• C#基础 基本语法5



    第十一章
    1、集合:控制他们包含的对象的访问、搜索和排序等
    数组一旦创建好大小就是固定的,不能在现有的数组末尾添加新项,除非创建一个新的数组。
    2、C#的数组实现为System.Array类的实例,他们只是集合类的一种类型。
    集合类一般用于处理对象列表,其功能比简单数组要多,功能大多是通过实现System.Collections名称空间中的接口而获得的。
    集合类的功能可以通过接口实现,该接口不仅没有限制我们使用基本集合类,相反还可以创建自己的定制集合类
    System.Collections名称空间中的几个接口提供了基本的集合功能
    IEnumerable可以迭代集合中的想
    ICollection可以或许集合中项的个数、并能把项复制到一个简单数组类型中
    Ilist继承于IEnumerable和ICollection提供了集合项列表允许访问这些项,病提供其他一些与项列表相关的基本功能
    IDictionary继承于IEnumerable和ICollection但提供了可通过键值而不是索引访问的列表项。
    ---------------System.Array类实现了IList、ICollection、IEnumerable但不支持List的一些高级功能,它表示大小固定的项列表


    集合创建,不需要初始化大小
    数组:Animal[] animalArray=new Animal[2];
    集合:ArrayList animalArrayList=new ArrayList();
    数组--------------------------//用两种方式完成初始化任务
    Cow myCow1=new Cow("Deirdre");
    animalArray[0]=myCow1; //用现有的对象来赋值
    animalArray[1]=new Chicken("ken");//创建一个新的Chicken对象来赋值
    --------------------------------------------------
    集合-----------------------------对于ArrayList集合它没有现成的项,也没有null引用的项,这样就不能以相同的方式给索引赋予新的实例。我们使用ArrayList对象的Add()方法添加新项。
    Cow myCow2=new Cow("Hayley");
    animalArrayList.Add(myCow2);
    animalArrayList.Add(new Chicken("Roy"));
    这种方式添加完项后就可以使用与数组相同的方式语法来改写他们
    animalArrayList[0]=new Cow("Alma");//但不能在这个示例中这么做
    -----------------------------------------------------------------------------------------
    因为System.Array实现了IEnumerable接口,这个接口的唯一方法GetEnumberator()可以迭代集合中的各项
    ----------------------------数组的表示
    foreach(Animal myAnimal in animalArray)
    {
    Console.WriteLine("New {0} object added to Array collection,"+"Name={1},myAnimal.ToString(),myAnimal.Name");
    }
    ----------------------------集合的表示,ArrayList对象也支持IEnumberable
    foreach(Animal myAnimal in animalArrayList)
    {
    Console.WriteLine("New {0} object added to Array collection,"+"Name={1},myAnimal.ToString(),myAnimal.Name");
    }
    ------------------------------------------------------------------------------------------
    -------------------接着使用数组的length属性
    Console.WriteLine("Array collection contains{0} objects.",animalArray.Length);
    -------------------ArrayList的集合要使用count属性
    Console.WriteLine("ArrayList colection contains {0} objects.",animalArrayList.Count);
    ----------------------------------------------------------------------------------------
    简单数组是强类型化的,可以直接访问它们所包含的项类型 animalArray[0].Feed();
    数组的类型是抽象类型Animal,因此不能直接调用由派生类提供的方法,必须使用数据类型转换
    ((Chicken)animalArray[1]).LayEgg();
    ArrayList集合石System.Object对象的集合(通过多态性赋值给Animal对象),所以必须对所有的数据类型转换:
    ((Animal)animalArrayList[0]).Feed();
    ((Chicken)animalArrayList[1]).LayEgg();
    ----------------------------------------------------------------------------------------
    索引符是一种特殊的类型属性,可以把他添加到一个类中,以提供类似于数组的访问
    Public Class Animals:CollectionBase
    {
    ..........
    public Animal this[int anmimalIndex]//this关键字与方括号一起使用
    {
    get
    {
    return (Animal)List[animalIndex]
    }
    set
    {
    List[animalIndex]=value;
    }
    }
    }


    3、
    public absract classAnimal
    {
    protected string name;
    public string Name
    {get{return name;}
    set{name=value;}
    }

    public Animal()
    {
    name="The animal with no name."
    }
    public Animal(string newName)
    {
    name=newName;
    }
    public void Feed()
    {
    Console.WriteLine("{0} has been fed.",name);
    }
    }
    -------------------Cow.cs代码
    namespace ch11Ex01
    {
    public class Cow:Animal
    {
    public void Milk()
    {
    Console.WriteLine("{0} has been milked.",name);
    }
    public Cow(string newName):base(newName)
    {
    }
    }
    }
    ----------------Chicken.cs代码
    namespace Ch11Ex01
    {
    public class Chicken:Animal
    {
    public void LayEgg()
    {
    Console.WriteLine("{0} has laid an agg.",name);
    }
    public Chicken(string newName):base(newName)
    {
    }
    }
    }
    ----------------------------Program.cs代码
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.linq;
    using System.Text;

    namespace Ch11Ex01
    {
    class Program
    {
    static void Main(string[] args)
    {
    Console.WriteLine("Creat an Array type collection of Animal"+"objects and use it:");
    Animal[] animalArry=new Animal[2];
    Cow myCow1=new Cow("Deirdre");
    animalArray[0]=mycow1;
    animalArray[1]=new Chicken("Ken");
    foreach(Animal myAnimal in animalArray)
    {
    Console.WriteLine("New {0}");
    }
    }
    }
    }

    ------------------------------------------------------------------------------------------
    1、类型比较
    GetType()所有的类都从System.Object继承,这个方法和typeof()运算符一起使用
    if(myObj.GetType()==typeof(MyComplexClass))
    {
    //myobj is an instance of the class MyComplexClass.
    }

    封箱:把值类型转换为System.Object,或者转换为由值类型实现的接口类型
    1、允许在项的类型是object的集合(ArrayList)中使用值类型
    2、有一个内部机制允许在值类型上调用object 例如int和结构
    拆箱:相反的转换类型
    1、访问值类型必须进行拆箱
    把这种类型结构封箱在object类型中,其中创建了一个类型为MyStruct的新变量valType,并把一个值赋予这个结构的Val成员,然后把它封箱在object类型的变量refType中
    struct MyStruct
    {
    public int Val;
    }
    MyStruct valType1=new MyStruct();
    valType.Val=5;
    object refType=valType1;
    以这种方式封箱变量而创建对象,包含值类型变量的一个副本的引用,而不包含源值类型变量的引用。
    ----------要进行验证可以修改源结构的内容。把对象中包含的结构拆箱到新变量中,检查其内容
    valType.Val=6;
    Mystruct valType2=(MyStruct)refType;
    Console.WriteLine("valType2.val={0}",valType2.val);//执行结果为5
    -----------------------------------------------------------------------------------------
    若把Struct改为一个类,不考虑这个类名不适合的情况
    class MyStruct
    {
    public int Val;
    }//这样就会得到valType2.Val=6;
    //也可以吧值类型封箱到一个接口类型中,只要他们实现这个接口即可,在MyStruct类型实现IMInterface

    interface IMyInterface
    {
    }
    struct MyStuct:IMyInterface
    {
    public int Val;
    }
    //接着把结构封箱到一个IMyInterface类型中
    MyStuct valType1=new MyStuct();
    IMyInterface refType=valType1;
    //然后使用一般的数据类型转换语法拆箱它:
    Mystuct ValType=(MyStruct)refType;
    --------封箱是隐式的,拆箱需要显示的数据类型转换

    2、使用is运算符比较annimal类型的对象,如果对象时3中类型的一种(不仅仅是Animal),is就会返回true
    P266
    3、值比较

    要重载运算符语法必须是静态的,操作数的类型与定义运算符的类相同,但也可以定义处理混合类型的运算符:
    public class AddClass1
    {
    public int val;
    }//这仅是int值的一个包装器(wrapper)但可以用于说明原理
    下面代码不能编译
    AddClass1 op1=new AddClass1();
    op1.val=5;
    AddClass1 op2=new AddClass1();
    op2.val=5;
    AddClass1 op3=op1+op2;
    错误是+运算符不能用于应用AddClass1类型的操作数,因为我们尚未定义要执行的操作
    AddClass1 op1=new AddClass1();
    op1.val=5;
    AddClass1 op2=new AddClass1();
    op2.val=5;
    bool op3=op1==op2;//也是得不到结果,即使相等op3也是false
    ------------------------------------------------------------------------------------
    public class AddClass1
    {
    public int val;
    public static AddClass1 operator+(AddClass1 op1,AddClass1 op2)
    {
    AddClass1 returnVal=new AddClass1();
    returnVal.val=op1.val+op2.val;
    return returnVal;
    }
    }
    ---------------------------------------------------------------------------------
    重载一元运算符合二元运算符
    public class AddClass1
    {
    public int val;
    public static AddClass1 operator+(AddClass1 op1,AddClass1 op2)
    {
    AddClass1 retrunVal=new AddClass();
    retrunVal.val=op1.val+op2.val;
    retrun retrunVal;
    }
    public static AddClass1 operator-(AddClass1 op1)
    {
    AddClass1 returnVal=new AddClass1();
    returnVal.val=-op1.val;
    return returnVal;
    }
    }
    -----------------------------------------------------------------------------------
    public class AddClass1
    {
    public int val;

    public static AddClass3 operator+(AddClass1 op1,AddClass2 op2)
    {
    AddClass3 returnVal=new AddClass3();
    retrunVal.val=op1.val+op2.val;
    return retrunVal;
    }

    public class AddClass2
    {
    public int val;
    }

    public class AddClass3
    {
    public int val;
    }
    }
    //下面的代码就可以执行
    AddClass1 op1=new AddClass1();
    op1.val=5;
    AddClass2 op2=new AddClass2();
    op2.val=5;
    AddClass3 op3=op1+op2;
    -----------------------如果重载true和false运算符,就可以在布尔表达式中使用类,例如,if(op1)
    --------------------------------------------------------------------------------------
    4、不能重载赋值运算符。不能重载&&和||,在计算机中使用&和| 所以重载&和|就够了
    <>必须成对重载
    -----------------------------------------------------------------------------------
    在许多情况下,可以在这些运算符中调用其他运算符,以减少代码的数量和可能发生的错误。
    public class AddClass1
    {
    public int val;
    public static bool operator>=(AddClass1 op1,AddClass2 op2)
    {
    retrun(op1.val>=op2.val);
    }

    public static bool operator<(AddClass1 op1,AddClass2 op2)
    {
    return!=(op1>=op2);
    }
    }
    ------------------------------------------------------------------------------------
    对于==和!=常常需要重写Object.Equals()和Object.GetHashCode();
    public class AddClass1
    {
    public int val;
    public static bool operator==(AddClass1 op1,AddClass1 op2)
    {
    return (op1.val==op2.val);
    }
    public static bool operator !=(AddClass1 op1,AddClass1 op2)
    {
    return !(op1==op2);
    }
    public override bool Equals(object op1)
    {
    return val==((AddClass1)op1).val;
    }
    public override int GetHashCode()//GetHashCode可以根据状态获取唯一的int值,这里使用val
    { //因为它也是一个int值
    return val;
    }
    }
    -------------------------------------------------------------------------------------
    转换
    重载转换运算符。
    类型之间的隐式转换
    ConvClass1 op1=new ConClass1();
    ConvClass2 op2=op1

    基本集合可以包含在类似ArrayList这样的类中,但这样的集合是没有类型化的,所以要把object项转换为集合实际存储的对象类型。
    泛型不限于类,可以有泛型接口、泛型方法、甚至泛型委托
    泛型允许灵活的创建类型,处理一种或多种特定类型的对象

    2、System.Collections.Geberic名称空间
    System名称空间包含.NET应用程序使用的大多数基本类型
    System.Text名称空间包含与自负串处理和编码相关的类型
    System.Linq----------------
    System.Collections.Generics;中两个类型List<T>

    List<T> myCollection=new List<T>();


    3、多态类型允许把派生类型对象放在你基类型的变量中
    Cow myCow=new Cow("Geronimo");
    Animal myAnimal=myCow;
    其中把Cow类型的对象放到Animal类型的变量中,这是可行的。因为Cow派生自Animal

    IMthianePrduce<Cow> cowMethaneProducer=myCow;
    IMethaneProducer<Animal> animalMethaneProducer=cowMethaneProducer;

    使用泛型,System.Collections.Generic名称空间中的类型,这个名称空间已在代码中出现多次,因为默认情况下,

    泛型的概念:
    基本集合可以包含在私立AaaryList这样的类中

    1、运算符
    using MyNameSpaceAlias=MyRootNamespace.MyNestedNamespace;
    namespace MyRootNamesoace
    {
    namespace MyNamespaceAlias
    {
    public class MyClass
    {
    }
    }

    namespace MyNetedNamespace
    {
    public class MyClass
    {
    }
    }
    }
    MyNameSpaceAlias::MyClass使用::这个运算符会迫使编译器使用using语句定义的别名
    因此代码会指向MyRootNamespace.MyNestedNamespace.MyClass
    ::还可以和global关键字一起使用,它实际上是顶级根名称空间的别名
    global::System.Collections.Gneric.List<int>
    namespace MyRootNamespace
    {
    namespace System
    {
    namespace Collections
    {
    namespace Generic
    {
    class List<T>
    {
    }
    }
    }
    }
    }//应避免使空间的名称与已有的.NET名称空间,但这个问题只在大项目中才会出现
    使用::和global关键字可能是访问所需类型的唯一方式。
    2、异常的基类
    System.Exception;在应用程序中有时可以从这个基类中派生自己的异常类,并使用它们,而不是使用标准的异常。
    System名称空间中有两个基本的异常类
    AppplicationException 由开发人员用于派生自己的异常类
    SystemException 用作.NET FrameWork预定义的异常的基类
    3、给CardLib添加定制异常
    定制异常最好通过Deck.GetCard();方法目前就会抛出一个标准的.NET异常
    4、public class CardOutOfRangeException:Exception
    {
    private Cards deckContents;
    public Cards DeckContents
    {
    get
    {
    return deckContents;
    }
    }
    public CardOutOfRangeException(Cards sourceDeckContents):base("There are only 52 cards in the deck.");
    {
    deckContents=sourceDeckContents;
    }
    }//

    在Deck.cs中添加抛出该异常的代码,替换原来的标准异常
    public Card GetCard(int cardNum)
    {
    if(cardNum>=0&&cardNum)
    return cards[cardNum];
    else
    throw new CardOutOfRangeException(cards.Clone() as Cards);
    }

    Deck deck1=new Deck();
    try
    {
    Card myCard=deck1.GetCard(60);
    }
    catch(CardOutof)

    }

    1、初始化器提供了一种简化代码的方式
    public class Curry
    {
    public string MainIngredient{get;set;}
    public string Style{get;set;}
    public int Spiciness{get;set;}
    }
    //这个类有三个属性,用自动属性语法来定义
    实例化和初始化这个类的一个对象实例
    Curry tastyCurry=new Curry();
    tastyCurry.MainIngredient="painr tikka";
    tastyCurry.Style="jalfrezi";
    tastyCurry.Spiciness=8;
    --------------------------------------------------其实就是简化上面的代码--------------
    如果类定义中未包含构造函数,这段代码就使用C#编译器提供的默认无参数构造函数
    public class Curry
    {
    public Curry(stiring mainIngredient,string style,int spiciness)
    {
    MainIngredient=mainIngredient;
    Style=style;
    Spiciness=spiciness;
    }
    }
    这样就可以编写代码,把实例化和初始化合并起来,它会强制使用Curry类的代码使用这个构造函数 ,这将阻止前面无参数构造函数的代码运行
    Curry tastyCurry=new Curry("panir tikka","jalfrezi",8);
    ------------------------------------------------------------------------------------------
    2、
    public class Curry
    {
    public Curry()
    {
    }
    .....
    }现在可以用任意方式实例化和初始化Curry类,

    Curry tastyCurry=new Curry
    {
    MainIngredient="panir tikka",
    Style="jalfrezi";
    Spiciness=8,
    Origin=new Restaurant
    {
    Name="King's Balti",
    Location="Youk Road",
    Rating=5
    }
    };

    4、初始化数组,合并实例化和初始化数组的简洁方式 int[] myIntArray=new int[5]{5,9,10,2,99};
    集合初始化器只是把语法扩展到集合上List<int> myIntCollection= new List<int>{5,9,10,2,99};
    List<Curry> curries=new List<Curry>();
    curryies.Add(new Curry("Chicken","Pathia",6));
    curryies.Add(new Curry("Vegetable","Korm",3));
    curryies.Add(new Curry("Prawn","Vindaloo",9));
    -------------------------------------------- 等价于
    List<Curry> moreCurries=new List<Curry>;
    {
    new Curry
    {
    MainIngredient="Chicken",
    Style="Pathia",
    Spiciness=6
    },
    new Curry
    {
    MainIngredient="Vegetable",
    Style="Korma",
    Spiciness=3
    },
    new Curry
    {
    MainIngredient="Prawn",
    Style="Vindaloo",
    Spiciness=9
    }
    }-------------------------------非常适合主要用于数据表示的类型
    5、类型推理
    int myInt=5;
    Console.WriteLine(myInt);
    C#3.0引入新关键字var,可以替代前面代码中的type
    var<varName>=<value>;
    用var时,并不是声明了一个没有类型的变量,也不是声明了一个类型可以变化的变量,否则C#就不再是强类型化的语言了,我们只需要利用编译器确定变量的类型即可。
    6、编译器不能确定var声明的变量类型,代码就不会编译,在用var声明变量时,必须同时初始化该变量,因为没有初始化值,编译器就不能确定变量的类型。所以 var myVar;就不能运行

    var可以通过数组初始化器来推断数组的类型
    var myArray=new []{4,5,2};
    在这个代码中,myArray的类型被隐式的设置为int[],在用这种方式隐式指定数组的类型时,初始化器中使用的数组元素必须是1、相同的类型2、相同的引用类型或空3、所有元素的类型都可以隐式的转换为一个类型
    xxxxxx var myArray=new[]{4,"not an int",2};
    xxxxxx var myArray=new[]{4,null,2};
    但可以使用标准的数组初始化器,使如下代码编译。
    var myArray=new int?[]{4,null,2};

    注意:var不能用于类名,这意味着如果其作用域中在同一个名称空间或引用的名称空间中有一个var类,就不能使用var关键字的隐式类型化功能

    6、匿名类型是简化这个编程模型的一种方式,理念是使用C#编译器根据要存储的数据自动创建类型,而不是定义简单的数据存储类型。
    可以使用下方式实例化Curry
    Curry curry=new Curry
    {
    MainIngredient="Lamb",
    Style="Dhansak",
    Spiciness=5
    };
    也可以使用匿名类型
    var curry=new
    {
    MainIngredient="Lamb",
    Style="Dhansak",
    Spiciness=5
    }
    7、动态查找var关键字本身并不是一个类型,所以没有违反C#的强类型化方法论
    8、dynamic类型:它与var不同,他是类型,所以声明时无需初始化他们
    dynamic myDynamicVar;
    dynamic仅在编译期间存在,运行期间会被System.Object类型代替

  • 相关阅读:
    P3383 【模板】线性筛素数
    POJ2431-Expedition【优先队列+贪心】
    HDU1087
    HDU1029
    最小生成树之Kruskal算法
    AC自动机模板
    328闯关解析
    php可获取客户端信息
    $( ).focus()与$( )[0].focus()区别
    RegExp类型和text()方法
  • 原文地址:https://www.cnblogs.com/d685600/p/3650366.html
Copyright © 2020-2023  润新知