• C# 数组(5) 持续更新


    同一类型和不同类型的多个对象

    使用同一类型的多个对象,使用集合和数组。

    使用不同类型的多个对象,使用Tuple(元组)。

    初始化数组

    int[] myArray = new int[4];

    myArray 存放在栈中,而 myArray 的内容 放在 托管堆。

    声明数组后,必须为数组分配内存,以保存数组的所有的元素。数组是引用类型,必须给它分配堆上的内存。

    如果不知道数组包括多少元素,可以使用集合。

    还可以用数组初始化器。

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

    访问数组

    myArray[0] = 12;
    myArray[1] = 24;

    如果使用错误的索引值,会抛出 IndexOutOfRangeException 错误。

    遍历数组

    int[] myArray = new int[4]{1,2,3,4};
    for (int i = 0; i < myArray.Length; i++)
    {
        Console.WriteLine("{0}",myArray[i]);
    }
    int[] myArray = new int[4]{1,2,3,4};
    foreach (int val in myArray)
    {
        Console.WriteLine("{0}",val);
    }

    foreach 语句利用了本章 IEnumerable 和 IEnumerator 接口。

    使用引用类型

    Person[] myPersons = new Person[2];
    myPersons[0] = new Person() {FirstName = "FirstName1", LastName = "LastName1"};
    myPersons[1] = new Person() { FirstName = "FirstName2", LastName = "LastName2" };
    Person[] myPersons =
    {
        new Person {FirstName = "FirstName1", LastName = "LastName1"},
        new Person {FirstName = "FirstName2", LastName = "LastName2"}
    };

    多维数组

    int[,] mInts = new int[2,2];
    mInts[0, 0] = 1;
    mInts[0, 1] = 2;
    mInts[1, 0] = 3;
    mInts[1, 1] = 4;
    int[,] mInts =
    {
        {0, 1},
        {0, 2},
        {1, 1},
        {2, 2}
    };

    当然还可以声明三维数组

    int[,,] mInts = new int[2,2,2];
    mInts[0, 0, 0] = 0;
    mInts[0, 0, 1] = 1;
    mInts[0, 1, 0] = 2;
    mInts[0, 1, 1] = 3;
    mInts[1, 0, 0] = 4;
    mInts[1, 0, 1] = 5;
    mInts[1, 1, 0] = 6;
    mInts[1, 1, 1] = 7;
    int[,,] mInts =
    {
        {{0, 1}, {2, 3}},
        {{3, 4}, {5, 6}},
        {{7, 8}, {9, 10}}
    };

    锯齿数组

    int[][] jagged = new int[3][];

    在初始化锯齿数组是,只在第1对方括号中设置该数组包含的行数。定义各行中元素个数的第2个方括号设置为空,让数组每行包含不同元素个数,之后指定行中元素个数。

    int[][] jagged = new int[3][];
    jagged[0] = new int[2] {1, 2};
    jagged[1] = new int[3] {3, 4, 5};
    jagged[2] = new int[4] {6, 7, 8, 9};

    Array类

    方括号声明数组, 实际上派生一个自抽象基类Array新类。foreach语句迭代数组,实际就是调用 Array中的 GetEnumerator()。

    Array.LongLength 包含数组的元素个数超出了整数的取值范围,就可以使用LongLength属性来获得元素的个数。

    Array.Rank 获得数组的维数。

    创建数组

    Array intArray1 = Array.CreateInstance(typeof(int),5);
    for (int i = 0; i < 5; i++)
    {
        intArray1.SetValue(2 + i,i);
    }
    
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(intArray1.GetValue(i));
    }
    
    int[] intArray2 = (int[]) intArray1;

    创建多维数组

    int[] lengths = {2, 3};
    int[] lowerBounds = {1, 10};
    Array racers = Array.CreateInstance(typeof(Person),lengths,lowerBounds);

    复制数组

    数组实现ICloneable接口,然后调用Clone返回浅副本。

    int[] intArray1 = {1, 2, 3};
    int[] intArray2 = (int[])intArray1.Clone();

    copy必须传递足够元素的数组。

    有时也需要深度克隆,但克隆的时候,要仔细思考一下,是否真的需要克隆。 

    排序

    int[] intArray1 = {99, 6, 3};
    Array.Sort(intArray1);
    foreach (var i in intArray1)
    {
        Console.WriteLine(i);
    }

    如果数组是自定义类,那么类就要实现Icomparable接口

    public class Person: IComparable<Person>
    {
    
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public int CompareTo(Person other)
        {
            if (other == null) return 1;
            int result = String.CompareOrdinal(this.LastName, other.LastName);
            if (result == 0)
            {
                result = String.CompareOrdinal(this.FirstName, other.FirstName);
            }
            return result;
        }
    
        public override string ToString()
        {
            return String.Format("{0} {1}",FirstName,LastName);
        }
    }

    对象相等,方法返回0。小于 返回 小于0的值 ,大于返回 大于0的值。

    如果不能修改类,还可以新类里 实现 IComparer 或 IComparer<T> 实现接口。

    public enum PersonCompareType
    {
        FirstName,
        LastName
    }
    
    public class PersonComparer : IComparer<Person>
    {
        private PersonCompareType compareType;
    
        public PersonComparer(PersonCompareType compareType)
        {
            this.compareType = compareType;
        }
    
    
        #region IComparer<Person> Members
    
        public int Compare(Person x, Person y)
        {
            if (x == null) throw new ArgumentNullException("x");
            if (y == null) throw new ArgumentNullException("y");
    
            switch (compareType)
            {
                case PersonCompareType.FirstName:
                    return String.Compare(x.FirstName, y.FirstName, StringComparison.Ordinal);
                case PersonCompareType.LastName:
                    return String.Compare(x.LastName, y.LastName, StringComparison.Ordinal);
                default:
                    throw new ArgumentException(
                          "unexpected compare type");
            }
        }
    
        #endregion
    }
    Array.Sort(persons, 
        new PersonComparer(PersonCompareType.FirstName));
    
    foreach (Person p in persons)
    {
        Console.WriteLine(p);
    }

    数组协变

    数值支持协变。这表示数组可以声明为基类,其派生类型的元素可以赋予数组元组。

    static void TestArray(object[] objects)

    这里就可以传入 Person[] 参数进去了。

    注意,数组协变只能用于引用类型,不能用于值类型。另外如果object[],被赋予了 Person[] 。就不能赋值其他类型的值了,否则运行时,会出现 ArrayTypeMismatchException 的异常。

    ArraySegment<T>

    ArraySegment表示数组的一部分。

    static void Main(string[] args)
    {
        int[] ar1 = {0, 1, 2, 3, 4, 5, 6};
        int[] ar2 = { 0, 1, 2, 3, 4, 5, 6 };
    
        ArraySegment<int>[] setmentInts = new ArraySegment<int>[2]
        {
            new ArraySegment<int>(ar1,0,3), 
            new ArraySegment<int>(ar2,3,3), 
        };
    
        int sum = SumOfSegments(setmentInts);
        Console.WriteLine(sum);
    }
    
    static int SumOfSegments(ArraySegment<int>[] segments)
    {
        int sum = 0;
        foreach (var segment in segments)
        {
            //for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
            //{
            //    sum += segment.Array[i];
            //}
    
            foreach (var value in segment)
            {
                sum += value;
            }
        }
        return sum;
    }

    数组段不复制原数组的元素,但原数组可以通过ArraySegment<T>访问。如果数组段的元素改变了,这些变换就会反映到原数组中。

    枚举

    数组或集合实现带 GetEumerator方法的IEumerable 接口。 GetEumberator 方法返回一个实现Ieumerable 接口的枚举。然后 foreach语句就可以使用Ieumerable接口迭代集合。

    IEnumerator接口

    foreach使用IEnumerator接口的方法和属性,迭代集合中的所有方法。为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true。如果集合不再有更多的元素,该方法返回false。

    这个接口的泛型版本IEnumerator<T> 派生字接口 IDispose ,因此定义了 Dispose 方法,来清空枚举器占用的资源。

    IEnumerator 接口还定义了 Reset() 方法,以与 COM 交互操作。

    foreach语句

    C#的 foreach 语句 不会解析为 IL代码中的 foreach语句。 C#编译器会把 foreach语句转换为 IEnumerator接口的方法和属性。

    foreach (var value in ar1)
    {
        Console.WriteLine(value);
    }

    解析为

    int[] ar1 = {0, 1, 2, 3, 4, 5, 6};
    int[] ar2 = { 0, 1, 2, 3, 4, 5, 6 };
    
    IEnumerator enumerator = ar1.GetEnumerator();
    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }

    yield

    yield可以创建枚举器,yield return语句返回集合一个元素,并移动到下一个元素上。yield break 可停止迭代。

    public class SimpleConllection : IEnumerable<string>
    {
        public IEnumerator<string> GetEnumerator()
        {
            yield return "Hello";
            yield return "World";
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    
    static void Main(string[] args)
    {
        SimpleConllection simpleConllection = new SimpleConllection();
        foreach (string s in simpleConllection)
        {
            Console.WriteLine(s);
        }
    }

    包含yield语句的方法或属性称为迭代快,迭代块必须声明返回IEnumerator 和 IEnumerable 接口,或者这些接口的泛型版本。这个块可以包含多条 yield return 语句 或 yield break 语句。但不能包含 return 语句。

    使用迭代块,编译器会生成 yield 类型,其中包含一个状态机,代码如下

    public class SimpleConllection
    {
        public IEnumerator GetEnumerator()
        {
            return new Enumerator(0);
        }
    
        public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable
        {
            private int state;
            private string current;
    
            public Enumerator(int state)
            {
                this.state = state;
            }
    
            bool System.Collections.IEnumerator.MoveNext()
            {
                switch (state)
                {
                    case 0:
                        current = "Hello";
                        state = 1;
                        return true;
                    case 1:
                        current = "World";
                        state = 2;
                        return true;
                    case 2:
                        break;
                }
                return false;
            }
    
            public void Dispose()
            {
               
            }
    
            public void Reset()
            {
               
            }
    
            public string Current { get; private set; }
    
            object IEnumerator.Current
            {
                get { return current; }
            }
        }
    }

    yield 语句 会生成一个枚举器,而不仅仅生成一个包含的项的列表。这个枚举器通过 foreach 语句调用。foreach中访问每一项是,就会访问枚举器。这样迭代大数据时,无须一次把所有的数据读入内存。

    元组 

    数组存储相同类型的对象,元组存放不同类型的对象。.net 4.0 中 定义了 8个泛型Tuple类和一个静态Tuple类。用于创建Tuple。

    http://blog.csdn.net/limlimlim/article/details/7835926

    private static Tuple<int, int> Divide(int dividend, int divisor)
    {
        return Tuple.Create<int, int>(dividend, divisor);
    }
    
    static void Main(string[] args)
    {
        Tuple<int, int> result = Divide(13, 2);
        Console.WriteLine("result of divison:{0}," +
            "reminder:{1}", result.Item1, result.Item2);   
    }

    当然 元组 还可以套用 元组。

    http://blog.csdn.net/limlimlim/article/details/7835926

    数组和元组 都实现了 IStructuralComparable,IStructuralEquatable 接口。

    IStructuralEquatable 用于比较两个元组或数组是否有相同的内容。

    IStructuralEquatable 用于元组或数组排序。

    Tuple 也提供了 Equals

    http://www.tuicool.com/articles/iqMv2i

  • 相关阅读:
    日志文件压缩
    Exchange2010 部署
    预读取页面 Prefetching pages
    利用Response的WriteFile方法输出一些文件
    事务记录工作中遇到的问题
    Orchard源码分析(7.1):Routing(路由)相关
    关于挑库规则的问题
    Oracle认证考试:EBS模块中文名称及英文缩写
    Oracle EBS 实施方法论扫盲:都有哪些实施方法论
    [二次开发] EBS R12 探索之路【EBS 经典SQL分享】
  • 原文地址:https://www.cnblogs.com/z888/p/5780619.html
Copyright © 2020-2023  润新知