美文网首页
70-483.C4O3-5.Implement data acc

70-483.C4O3-5.Implement data acc

作者: 小镭Ra | 来源:发表于2018-10-29 12:21 被阅读16次

    Note Links

    Objective 4.3: Query and manipulate data and objects by using LINQ

    Language features that make LINQ possible

    Implicitly typed variables

    Dictionary<string, IEnumerable<Tuple<Type, int>>> data =  
        new Dictionary<string, IEnumerable<Tuple<Type, int>>>(); 
    var implicitData = new Dictionary<string, IEnumerable<Tuple<Type, int>>>();
    

    Implicit typing can be used to avoid repetition. But it's better to avoid implicit typing when the type of variable is unclear:

    var whatsMyType = GetData();    // avoid doing this
    

    Object initialization syntax

    LISTING 4-49 Using an object initializer

    // Create and initialize a new object in one step 
    Person p = new Person 
    {  
        FirstName ="John", 
        LastName = "Doe" 
    };
    

    LISTING 4-50 Using a collection initializer

    var people = new List<Person> 
    { 
        new Person 
        { 
            FirstName = "John", 
            LastName = "Doe" 
        },   
        new Person 
        { 
            FirstName = "Jane", 
            LastName = "Doe" 
        } 
    };
    

    Lambda expressions

    LISTING 4-51 Using an anonymous method

    Func<int, int> myDelegate = 
        delegate(int x) 
        { 
            return x * 2; 
        }; 
    Console.WriteLine(myDelegate(21)); // Displays 42
    

    Lambda version:

    Func<int, int> myDelegate = x => x * 2; 
    Console.WriteLine(myDelegate(21)); // Displays 42
    

    Extension methods

    LINQ is entirely based on extension methods. They are defined in the System.Linq.Enumerables class.

    Anonymous types

    LISTING 4-53 Creating an anonymous type

    var person = new 
    { 
        FirstName = "John", 
        LastName = "Doe" 
    }; 
     
    Console.WriteLine(person.GetType().Name); // Displays "<>f__AnonymousType0`2"
    

    Anonymous types are used in LINQ when you create a so-called projection. This means that you select certain properties from a query and form a specific type for it.

    Using LINQ queries

    Standard LINQ query operators

    101 LINQ Samples

    The standard query operators are:

    • All
    • Any
    • Average
    • Cast
    • Count
    • Distinct
    • GroupBy
    • Join
    • Max
    • Min
    • OrderBy
    • OrderByDescending
    • Select
    • SelectMany
    • Skip
    • SkipWhile
    • Sum
    • Take
    • TakeWhile
    • ThenBy
    • ThenByDescending
    • Where

    LISTING 4-60 Using group by and projection

    var result = from o in orders 
                 from l in o.OrderLines 
                 group l by l.Product into p 
                 select new 
                     { 
                        Product = p.Key, 
                        Amount = p.Sum(x => x.Amount) 
                     };
    

    LISTING 4-61 Using join

    string[] popularProductNames = { "A", "B" }; 
    var popularProducts = from p in products 
                          join n in popularProductNames on p.Description equals n 
                          select p;
    

    LISTING 4-62 Using Skip and Take to implement paging

    var pagedOrders = orders 
                    .Skip((pageIndex - 1) * pageSize) 
                    .Take(pageSize);
    

    LINQPAD

    How does LINQ work?

    LISTING 4-63 Implementing Where

    public static class LinqExtensions 
    { 
        public static IEnumerable<TSource> Where<TSource>( 
            this IEnumerable<TSource> source, 
            Func<TSource, bool> predicate) 
        { 
            foreach (TSource item in source) 
            { 
                if (predicate(item)) 
                { 
                    yield return item; 
                } 
            } 
        } 
    }
    

    Using LINQ to XML

    LISTING 4-65 Querying some XML by using LINQ to XML

    XDocument doc = XDocument.Parse(xml); 
    IEnumerable<string> personNames = from p in doc.Descendants("Person") 
                                      select (string)p.Attribute("firstName")  
                                         + " " + (string)p.Attribute("lastName"); 
    foreach (string s in personNames) 
    { 
        Console.WriteLine(s); 
    }
    // Displays: 
    // John Doe 
    // Jane Doe
    

    LISTING 4-66 Using Where and OrderBy in a LINQ to XML query

    XDocument doc = XDocument.Parse(xml); 
    IEnumerable<string> personNames = from p in doc.Descendants("Person") 
                                      where p.Descendants("PhoneNumber").Any() 
                                      let name = (string)p.Attribute("firstName")  
                                                  + " " + (string)p.Attribute("lastName") 
                                      orderby name 
                                      select name;
    

    LISTING 4-67 Creating XML with the XElement class

    XElement root = new XElement("Root", 
                new List<XElement> 
                { 
                    new XElement("Child1"), 
                    new XElement("Child2"), 
                    new XElement("Child3") 
                }, 
                new XAttribute("MyAttribute", 42)); 
    root.Save("test.xml"); 
     
    //Outputs: 
    //<Root MyAttribute="42"> 
    //    <Child1 />  
    //    <Child2 />  
    //    <Child3 />  
    //</Root>
    

    LISTING 4-68 Updating XML in a procedural way

    XElement root = XElement.Parse(xml); 
     
    foreach (XElement p in root.Descendants("Person")) 
    { 
        string name = (string)p.Attribute("firstName") + (string)p.Attribute("lastName"); 
        p.Add(new XAttribute("IsMale", name.Contains("John"))); 
        XElement contactDetails = p.Element("ContactDetails"); 
        if (!contactDetails.Descendants("PhoneNumber").Any()) 
        { 
            contactDetails.Add(new XElement("PhoneNumber", "001122334455")); 
        } 
    }
    

    LISTING 4-69 Transforming XML with functional creation

    XElement root = XElement.Parse(xml); 
     
    XElement newTree = new XElement("People", 
        from p in root.Descendants("Person") 
        let name = (string)p.Attribute("firstName") + (string)p.Attribute("lastName") 
        let contactDetails = p.Element("ContactDetails") 
        select new XElement("Person", 
            new XAttribute("IsMale", name.Contains("John")), 
            p.Attributes(), 
            new XElement("ContactDetails", 
                contactDetails.Element("EmailAddress"), 
                contactDetails.Element("PhoneNumber")  
                    ?? new XElement("PhoneNumber", "112233455") 
            )));
    

    Objective summary

    • LINQ, which stands for Language Integrated Query, is a uniform way of writing queries against multiple data sources.
    • Important language features when working with LINQ queries are implicit typing, object initialization syntax, lambdas, extension methods, and anonymous types.
    • You can use LINQ with a method-based syntax and the query syntax.
    • LINQ queries are deferred-execution, which means that the query executes when it is first iterated.
    • You can use LINQ to XML to query, create, and update XML.

    Objective 4.4: Serialize and deserialize data

    Using XmlSerializer

    When working with the XmlSerializer, it's important that you mark your types with the [Serializable] attribute, part of the SerializableAttribute class.

    LISTING 4-70 Serializing an object with the XmlSerializer

    [Serializable] 
    public class Person 
    { 
        public string FirstName { get; set; } 
        public string LastName { get; set; } 
        public int Age { get; set; } 
    }
    XmlSerializer serializer = new XmlSerializer(typeof(Person)); 
    string xml; 
    using (StringWriter stringWriter = new StringWriter()) 
    { 
        Person p = new Person 
        { 
            FirstName = "John", 
            LastName = "Doe", 
            Age = 42 
        }; 
        serializer.Serialize(stringWriter, p); 
        xml = stringWriter.ToString(); 
    } 
     
    Console.WriteLine(xml); 
     
    using (StringReader stringReader = new StringReader(xml)) 
    { 
        Person p = (Person)serializer.Deserialize(stringReader); 
        Console.WriteLine("{0} {1} is {2} years old", p.FirstName, p.LastName, p.Age); 
    } 
     
    // Displays 
    //<?xml version="1.0" encoding="utf-16"?> 
    //<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    // xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    //  <FirstName>John</FirstName> 
    //  <LastName>Doe</LastName> 
    //  <Age>42</Age> 
    //</Person> 
    //John Doe is 42 years old
    

    You can configure how the XmlSerializer serializes your type by using attributes:

    • XmlIgnore
    • XmlAttribute
    • XmlElement
    • XmlArray
    • XmlArrayItem

    By default, each member is serialized as an XmlElement.

    LISTING 4-71 Using the XML attributes to configure serialization

    [Serializable] 
    public class Person 
    { 
        public string FirstName { get; set; } 
        public string LastName { get; set; } 
        public int Age { get; set; } 
    }
    [Serializable] 
    public class Order 
    { 
        [XmlAttribute] 
        public int ID { get; set; } 
     
        [XmlIgnore] 
        public bool IsDirty { get; set; } 
     
        [XmlArray("Lines")] 
        [XmlArrayItem("OrderLine")] 
        public List<OrderLine> OrderLines { get; set; } 
    } 
     
    [Serializable] 
    public class VIPOrder : Order 
    { 
        public string Description { get; set; } 
    } 
     
    [Serializable] 
    public class OrderLine 
    { 
        [XmlAttribute] 
        public int ID { get; set; } 
     
        [XmlAttribute] 
        public int Amount { get; set; } 
     
        [XmlElement("OrderedProduct")] 
        public Product Product { get; set; } 
    } 
     
    [Serializable] 
    public class Product 
    { 
        [XmlAttribute] 
        public int ID { get; set; } 
        public decimal Price { get; set; } 
        public string Description { get; set; } 
    }
    

    LISTING 4-72 Serializing a derived, complex class to XML

    private static Order CreateOrder() 
    { 
        Product p1 = new Product { ID = 1, Description = "p2", Price = 9 }; 
        Product p2 = new Product { ID = 2, Description = "p3", Price = 6 }; 
     
        Order order = new VIPOrder 
        { 
            ID = 4, 
            Description = "Order for John Doe. Use the nice giftwrap", 
            OrderLines = new List<OrderLine> 
            {  
                new OrderLine { ID = 5, Amount = 1, Product = p1}, 
                new OrderLine { ID = 6 ,Amount = 10, Product = p2}, 
            } 
        }; 
     
        return order; 
    }
    XmlSerializer serializer = new XmlSerializer(typeof(Order),  
       new Type[] { typeof(VIPOrder) }); 
    string xml; 
    using (StringWriter stringWriter = new StringWriter()) 
    { 
        Order order = CreateOrder(); 
        serializer.Serialize(stringWriter, order); 
        xml = stringWriter.ToString(); 
    } 
    using (StringReader stringReader = new StringReader(xml)) 
    { 
        Order o = (Order)serializer.Deserialize(stringReader); 
        // Use the order 
    }
    

    Using binary serialization

    LISTING 4-73 Using binary serialization

    [Serializable] 
    public class Person 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
        private bool isDirty = false; 
    } 
     
    Person p = new Person 
    { 
        Id = 1, 
        Name = "John Doe" 
    }; 
     
    IFormatter formatter = new BinaryFormatter(); 
    using (Stream stream = new FileStream("data.bin", FileMode.Create)) 
    { 
        formatter.Serialize(stream, p); 
    } 
     
    using (Stream stream = new FileStream("data.bin", FileMode.Open)) 
    { 
        Person dp = (Person)formatter.Deserialize(stream); 
    }
    

    Binary serialization creates a compact stream of bytes. One thing that's different compared with XML serialization is that private fields are serialized by default. Another thing is that during deserialization, no constructors are executed.

    LISTING 4-74 Using attributes to control serialization

    [Serializable] 
    public class Person 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
     
        [NonSerialized] 
        private bool isDirty = false; 
    }
    

    You can influence the serialization and deserialization process in four specific phases by using the following four attributes:

    • OnDeserializedAttribute
    • OnDeserializingAttribute
    • OnSerializedAttribute
    • OnSerializingAttribute

    LISTING 4-75 Influencing serialization and deserialization

    [Serializable] 
    public class Person 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
     
        [NonSerialized] 
        private bool isDirty = false; 
        [OnSerializing()] 
        internal void OnSerializingMethod(StreamingContext context) 
        { 
            Console.WriteLine("OnSerializing."); 
        } 
     
        [OnSerialized()] 
        internal void OnSerializedMethod(StreamingContext context) 
        { 
            Console.WriteLine("OnSerialized."); 
        } 
     
        [OnDeserializing()] 
        internal void OnDeserializingMethod(StreamingContext context) 
        { 
            Console.WriteLine("OnDeserializing."); 
        } 
     
        [OnDeserialized()] 
        internal void OnDeserializedMethod(StreamingContext context) 
        { 
            Console.WriteLine("OnSerialized."); 
        } 
    }
    

    A serialized object could expose private data that is security sensitive. Everyone who has permissions to deserialize the file can access your sensitive data. If you have a sensitive class, you should implement the ISerializable interface.

    LISTING 4-76 Implementing ISerializable

    [Serializable] 
    public class PersonComplex : ISerializable 
    { 
        public int Id { get; set; } 
        public string Name { get; set; } 
        private bool isDirty = false; 
     
        public PersonComplex() { } 
        protected PersonComplex(SerializationInfo info, StreamingContext context) 
        { 
            Id = info.GetInt32("Value1"); 
            Name = info.GetString("Value2"); 
            isDirty = info.GetBoolean("Value3"); 
        } 
     
        [System.Security.Permissions.SecurityPermission(SecurityAction.Demand,  
                                                        SerializationFormatter = true)] 
        public void GetObjectData(SerializationInfo info, StreamingContext context) 
        { 
            info.AddValue("Value1", Id); 
            info.AddValue("Value2", Name); 
            info.AddValue("Value3", isDirty); 
        } 
    }
    

    you should mark GetObjectData method with a SecurityPermission attribute (you can find this attribute in the System.Security.Permissions namespace) so that it is allowed to execute serialization and deserialization code.

    Using DataContract

    The most noticeable difference is that you use DataContractAttribute instead of SerializableAttribute. Another important difference is that members are not serialized by default. You have to explicitly mark them with the DataMember attribute.

    LISTING 4-77 Using a DataContract

    [DataContract] 
    public class PersonDataContract 
    { 
        [DataMember] 
        public int Id { get; set; } 
        [DataMember] 
        public string Name { get; set; } 
     
        private bool isDirty = false; 
    }
    

    LISTING 4-78 Using the DataContractSerializer

    PersonDataContract p = new PersonDataContract 
    { 
        Id = 1, 
        Name = "John Doe" 
    }; 
     
    using (Stream stream = new FileStream("data.xml", FileMode.Create)) 
    { 
        DataContractSerializer ser = new DataContractSerializer(typeof(PersonDataContract)); 
        ser.WriteObject(stream, p); 
    } 
     
    using (Stream stream = new FileStream("data.xml", FileMode.Open)) 
    { 
        DataContractSerializer ser = new DataContractSerializer(typeof(PersonDataContract)); 
        PersonDataContract result = (PersonDataContract)ser.ReadObject(stream); 
    }
    

    Using JSON serializer

    LISTING 4-79 Using the DataContractJsonSerializer

    [DataContract] 
    public class Person 
    { 
        [DataMember] 
        public int Id { get; set; } 
        [DataMember] 
        public string Name { get; set; } 
    } 
     
    Person p = new Person 
    { 
        Id = 1, 
        Name = "John Doe" 
    }; 
     
    using (MemoryStream stream = new MemoryStream()) 
    { 
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Person)); 
        ser.WriteObject(stream, p); 
     
        stream.Position = 0; 
        StreamReader streamReader = new StreamReader(stream); 
        Console.WriteLine(streamReader.ReadToEnd()); // Displays {"Id":1,"Name":"John Doe"} 
     
        stream.Position = 0; 
        Person result = (Person)ser.ReadObject(stream); 
    }    
    

    Objective summary

    • Serialization is the process of transforming an object to a flat file or a series of bytes.
    • Deserialization takes a series of bytes or a flat file and transforms it into an object.
    • XML serialization can be done by using the XmlSerializer.
    • You can use special attributes to configure the XmlSerializer.
    • Binary serialization can be done by using the BinaryFormatter class.
    • WCF uses another type of serialization that is performed by the DataContractSerializer.
    • JSON is a compact text format that can be created by using the DataContractJsonSerializer.

    Objective 4.5: Store data in and retrieve data from collections

    Using arrays

    LISTING 4-80 Using an array

    int[] arrayOfInt = new int[10]; 
     
    for (int x = 0; x < arrayOfInt.Length; x++) 
    { 
        arrayOfInt[x] = x; 
    } 
     
    foreach (int i in arrayOfInt) 
    { 
        Console.Write(i); // Displays 0123456789 
    }
    

    LISTING 4-81 Using a two-dimensional array

    string[,] array2D = new string[3, 2] { { "one", "two" }, { "three", "four" }, 
                            { "five", "six" } }; 
     
    Console.WriteLine(array2D[0, 0]); // one 
    Console.WriteLine(array2D[0, 1]); // two 
    Console.WriteLine(array2D[1, 0]); // three 
    Console.WriteLine(array2D[1, 1]); // four 
    Console.WriteLine(array2D[2, 0]); // five 
    Console.WriteLine(array2D[2, 1]); // six
    

    LISTING 4-82 Creating a jagged array

    int[][] jaggedArray =  
       { 
            new int[] {1,3,5,7,9}, 
            new int[] {0,2,4,6}, 
            new int[] {42,21} 
        };
    

    A jagged array is an array whose elements are arrays.

    Because arrays are reference types, the values of a jagged array have a default value of null.

    LISTING 4-82 Creating a jagged array

    int[][] jaggedArray =  
       { 
            new int[] {1,3,5,7,9}, 
            new int[] {0,2,4,6}, 
            new int[] {42,21} 
        };
    

    Understanding generic versus nongeneric

    If you use a value type as the type parameter for a generic collection, you need to make sure that you eliminate all scenarios in which boxing could occur. For example, if your value type does not implement IEquatable<T>, your object needs boxing to call Object.Equals(Object) for checking equality.

    Using List

    LISTING 4-83 Using IList<T> and ICollection<T>

    public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable 
    { 
            T this[int index] { get; set; } 
            int IndexOf(T item); 
            void Insert(int index, T item);     
            void RemoveAt(int index); 
    }
    public interface ICollection<T> : IEnumerable<T>, IEnumerable 
    { 
            int Count { get; }     
            bool IsReadOnly { get; } 
            void Add(T item);     
            void Clear();     
            bool Contains(T item);     
            void CopyTo(T[] array, int arrayIndex);     
            bool Remove(T item); 
    }
    

    LISTING 4-84 Using List<T>

    List<string> listOfStrings = 
        new List<string> { "A", "B", "C", "D", "E" }; 
     
    for (int x = 0; x < listOfStrings.Count; x++) 
        Console.Write(listOfStrings[x]); // Displays: ABCDE 
     
    listOfStrings.Remove("A"); 
     
    Console.WriteLine(listOfStrings[0]); // Displays: B 
     
    listOfStrings.Add("F"); 
    
    Console.WriteLine(listOfStrings.Count); // Displays: 5 
     
    bool hasC = listOfStrings.Contains("C"); 
     
    Console.WriteLine(hasC); // Displays: true
    

    Using Dictionary

    The Dictionary class is implemented as a hash table, which makes retrieving a value very fast, close to O(1).

    LISTING 4-85 Using Dictionary<TKey, TValue>

    Person p1 = new Person { Id = 1, Name = "Name1" }; 
    Person p2 = new Person { Id = 2, Name = "Name2" }; 
    Person p3 = new Person { Id = 3, Name = "Name3" }; 
     
    var dict = new Dictionary<int, Person>(); 
    dict.Add(p1.Id, p1); 
    dict.Add(p2.Id, p2); 
    dict.Add(p3.Id, p3); 
     
    foreach (KeyValuePair<int, Person> v in dict) 
    { 
        Console.WriteLine("{0}: {1}", v.Key, v.Value.Name); 
    } 
     
    dict[0] = new Person { Id = 4, Name = "Name4" }; 
     
    Person result; 
    if (!dict.TryGetValue(5, out result)) 
    { 
        Console.WriteLine("No person with a key of 5 can be found"); 
    }
    

    Using sets

    A set is a collection that contains no duplicate elements and has no particular order.

    LISTING 4-86 Using the ISet<T> interface

    public interface ISet<T> : ICollection<T>, IEnumerable<T>, IEnumerable 
    { 
            bool Add(T item); 
            void ExceptWith(IEnumerable<T> other); 
            void IntersectWith(IEnumerable<T> other); 
            bool IsProperSubsetOf(IEnumerable<T> other); 
            bool IsProperSupersetOf(IEnumerable<T> other); 
            bool IsSubsetOf(IEnumerable<T> other); 
            bool IsSupersetOf(IEnumerable<T> other); 
            bool Overlaps(IEnumerable<T> other); 
            bool SetEquals(IEnumerable<T> other); 
            void SymmetricExceptWith(IEnumerable<T> other); 
            void UnionWith(IEnumerable<T> other); 
    }
    

    LISTING 4-87 Using HashSet<T>

    public void UseHashSet() 
    { 
        HashSet<int> oddSet = new HashSet<int>(); 
        HashSet<int> evenSet = new HashSet<int>(); 
     
        for (int x = 1; x <= 10; x++) 
        { 
            if (x % 2 == 0) 
                evenSet.Add(x); 
            else 
                oddSet.Add(x); 
        } 
     
        DisplaySet(oddSet); 
        DisplaySet(evenSet); 
     
        oddSet.UnionWith(evenSet); 
        DisplaySet(oddSet); 
    } 
     
    private void DisplaySet(HashSet<int> set) 
    { 
        Console.Write("{"); 
        foreach (int i in set) 
        { 
            Console.Write(" {0}", i); 
        } 
        Console.WriteLine(" }"); 
    }
    

    Using queues and stacks

    A queue is first-in, first-out (FIFO) type of collection. It offers temporary storage.

    The Queue class has three important methods:

    • Enqueue adds an element to the end of the Queue, equivalent to the back of the line.
    • Dequeue removes the oldest element from the Queue, equivalent to the front of the line.
    • Peek Returns the object at the beginning of the Queue without removing it.

    LISTING 4-88 Using Queue<T>

    Queue<string> myQueue = new Queue<string>(); 
    myQueue.Enqueue("Hello"); 
    myQueue.Enqueue("World"); 
    myQueue.Enqueue("From"); 
    myQueue.Enqueue("A"); 
    myQueue.Enqueue("Queue"); 
     
    foreach (string s in myQueue) 
        Console.Write(s + " "); 
    // Displays: Hello World From A Queue
    

    A Stack is a last-in, first-out (LIFO) collection.

    A Stack has the following three important methods:

    • Push Add a new item to the Stack.
    • Pop Get the newest item from the Stack.
    • Peek Get the newest item without removing it.

    LISTING 4-89 Using Stack<T>

    Stack<string> myStack = new Stack<string>(); 
    myStack.Push("Hello"); 
    myStack.Push("World"); 
    myStack.Push("From"); 
    myStack.Push("A"); 
    myStack.Push("Queue"); 
     
    foreach (string s in myStack) 
        Console.Write(s + " "); 
    // Displays: Queue A From World Hello
    

    Choosing a collection

    The biggest differences between the collections are the ways that you access elements.

    List and Dictionary types offer random access to all elements. A Dictionary offers faster read features.

    A Queue and a Stack are used when you want to retrieve items in a specific order. The item is removed when you have retrieved it.

    Set-based collections have special features for comparing collections. They don't offer random access to individual elements.

    MORE INFO ABOUT COLLECTION TYPES

    Creating a custom collection

    LISTING 4-90 Inheriting from List<T> to form a custom collection

    public class PeopleCollection : List<Person> 
    { 
        public void RemoveByAge(int age) 
        { 
            for (int index = this.Count - 1; index >= 0; index--) 
            { 
                if (this[index].Age == age) 
                { 
                    this.RemoveAt(index); 
                } 
            } 
        } 
     
        public override string ToString() 
        { 
            StringBuilder sb = new StringBuilder(); 
            foreach (Person p in this) 
            { 
                sb.AppendFormat("{0} {1} is {2}", p.FirstName, p.LastName, p.Age); 
            } 
            return sb.ToString(); 
        } 
    }
    

    LISTING 4-91 Using a custom collection

    public class Person 
    { 
        public string FirstName { get; set; } 
        public string LastName { get; set; } 
        public int Age { get; set; } 
    } 
    Person p1 = new Person 
    { 
        FirstName = "John", 
        LastName = "Doe", 
        Age = 42 
    }; 
    Person p2 = new Person 
    { 
        FirstName = "Jane", 
        LastName = "Doe", 
        Age = 21 
    }; 
     
    PeopleCollection people = new PeopleCollection { p1, p2 }; 
    people.RemoveByAge(42); 
    Console.WriteLine(people.Count); // Displays: 1
    

    Objective summary

    • The .NET Framework offers both generic and nongeneric collections. When possible, you should use the generic version.
    • Array is the most basic type to store a number of items. It has a fixed size.
    • List is a collection that can grow when needed. It's the most-used collection.
    • Dictionary stores and accesses items using key/value pairs.
    • HashSet stores unique items and offers set operations that can be used on them.
    • A Queue is a first-in, first-out (FIFO) collection.
    • A Stack is a first-in, last-out (FILO) collection.
    • You can create a custom collection by inheriting from a collection class or inheriting from one of the collection interfaces.

    Chapter summary

    • You can use classes such as Drive, DriveInfo, Directory, DirectoryInfo, File, and FileInfo to work with the file system. All I/O uses Streams, which are an abstraction over a series of bytes.
    • Asynchronous code is important for long-running operations to improve responsiveness and scalability.
    • When working with a database, you can use ADO.NET to establish a connection, execute commands, and retrieve results.
    • The .NET Framework has support for working with XML by using classes such as XmlWriter, XmlReader, and XmlDocument, or by using LINQ to XML.
    • LINQ offers a uniform way of querying different data sources.
    • Serializing and deserializing is the process of transforming an object to a flat file or a series of bytes, and vice versa.
    • The .NET Framework offers a comprehensive set of collections that you can use in different scenarios.

    Note Links

    相关文章

      网友评论

          本文标题:70-483.C4O3-5.Implement data acc

          本文链接:https://www.haomeiwen.com/subject/kxlbtqtx.html