SoFunction
Updated on 2025-03-08

Collection, comparison and conversion of C# Introduction

1. Collection

Arrays in C# are executed as instances of classes, and they are one of the collection classes.
Collection classes are generally used to process object lists, and their functions are implemented through the interfaces in execution.

The functions of collections can be implemented through an interface, which can use basic basic collection classes or create custom collection classes.

There are many interfaces in the namespace that provide basic collection functions:

  • IEnumerable: Exposes enumerations that support simple iteration on non-generic collections
  • ICollection: Defines the size, enumeration number and synchronization method of all non-generic collections
  • IList: A non-generic collection of objects that can be accessed separately by index
  • IDictionary: A non-generic set representing key/value pairs

Classes inherit IList, ICollection, and IEnumerable. But it does not support some advanced features of IList, and it is a fixed-sized list of items.

1. Use collections

A class in which also executes IList, ICollection and IEnumerable interfaces, but unlike arrays, it is of variable size
Using a collection of classes (arrays), the array must be initialized with a fixed size.
For example:

Animal[] animalArray = new Animal[2];

Use a collection of classes, no need to initialize its size
For example:

ArrayList animalArrayList = new ArrayList();

This class has two constructors:
1 Copy the existing set as parameters to the new instance
2 Use an int parameter to set the capacity of the collection, but the actual content will automatically increase when the capacity exceeds the capacity.
Initialize the array, you need to assign the initialized object to this project.
For example:

Cow myCow1 = new Cow("Deirdre");
animalArray[0] = myCow1;
animalArray[1] = new Chicken("Ken");

The array can be initialized in these two ways

For ArrayList collection, you need to use the Add() method to add a new project.
For example:

Cow myCow2 = new Cow("Hayley");
(myCow2);
(new Chicken("Roy"));

After adding ten thousand items, you can rewrite them in the same syntax as the array.
For example:

animalArrayList[1] = new Chicken("Roy2")

Array array and ArrayList collection both support foreach structure to iterate.
For example:

foreach (Animal myAnimal in animalArray)
{
}

foreach (Animal myAnimal in animalArrayList)
{
}

Array array uses the Length attribute to obtain the number of items
For example:

int animalCount = ;

ArrayList collection uses the Count property to get the number of items

int animalCount2 = ;

Array arrays are strongly typed, and you can directly use the array type to store items.
That is, you can directly access the properties and methods of the project.
For example:
For arrays with type Animal, Feed() is a method of class Animal

animalArray[0].Feed();

However, for methods derived from Animal, they cannot be called directly, and they need to be cast.

((Chicken)animalArray[1]).LayEgg();

ArrayList collection is a collection of objects, assigned to Animal objects through polymorphism.
Data type conversion must be performed
For example:

((Animal)animalArrayList[0]).Feed();
((Chicken)animalArrayList[1]).LayEgg();

Use the Remove() and RemoveAt() methods to delete the project
Remove Remove the first match of a specific object from the ArrayList (the parameter is a specific object)
RemoveAt Removes the element at the specified index of ArrayList (the parameter is the index value)
After deleting an item, other items will be moved by one position in the array.

Use the AddRange() and InsertRange() methods to add multiple items at once.
AddRange Adds the element of ICollection to the end of the ArrayList
InsertRange Inserts an element in the collection at the specified index of the ArrayList.
For example:

(animalArray);

Use IndexOf() method to get the index value of the specified item
IndexOf Returns the zero-based index of the first match of an ArrayList or part of it.
You can directly access the options through the index value.
For example:

int iIndex =  (myCow1);
((Animal)animalArrayList[iIndex]).Feed();

2. Custom collection

Custom collections can be derived from a class
Recommended use of classes. The CollectionBase class has interfaces IEnumerable, ICollection, and IList

The List property can access the project through the Ilist interface. The InnerList property is used to store the ArrayList object of the project.

For example:

public class Animals : CollectionBase
 {
    public void Add(Animal newAnimal)
    {
        (newAnimal);
    }

    public void Remove(Animal oldAnimal)
    {
        (oldAnimal);
    }

    public Animals()
    {
    }
 }

This class is used to generate collections of type Animal, and its members can be accessed using foreach:

Animals animalCollection = new Animals();
(new Cow("Sarah"));
foreach (Animal myAnimal in animalCollection)
{
}

If you want to access the project as an index, you need to use the indexer

3. Index character

An indexer is a special type of property that can be added to a class to provide array-like access.
One of the most common usages is to perform a numeric index on the project

For example:
Add an index in the Animals collection

public class Animals : CollectionBase
{
     ...
     public Animal this[int animalIndex]
     {
         get
         {
             return (Animal)List[animalIndex];
         }
         set
         {
             List[animalIndex] = value;
         }
     }
 }

This keyword is with square brackets, and the index parameters are in square brackets.
Use an indexer for List and the type is declared because the IList interface returns an object.
Now you can access the project by indexing:

animalCollection[0].Feed();

4. Keyword value collection and IDictionary

Collections can also execute similar IDictionary interfaces, indexed through keyword values.
Using the base class DictionaryBase, it also executes the IEnumerable and ICollection interfaces, providing the same collection processing function for any collection.

For example:

public class Animals : DictionaryBase
 {
    public void Add(string newID, Animal newAnimal)
    {
        (newID, newAnimal);
    }

    public void Remove(string animalID)
    {
        (animalID);
    }

    public Animals()
    {
    }

    public Animal this[string animalID]
    {
        get
        {
            return (Animal)Dictionary[animalID];
        }
        set
        {
            Dictionary[animalID] = value;
        }
    }
}

This adds the Add() method, the Remove() method and a method to access the project through keywords.
where Dictionary is a list of elements contained in the DictionaryBase instance

DictionaryBase collection and CollectionBase collection work differently in foreach.
DictionaryBase provides a DictionaryEntry structure, and the object itself needs to be obtained through the Value member.
For example:
CollectionBase collection:

foreach (Animal myAnimal in animalCollection)
{
    ();
}

DictionaryBase collection:

foreach (DictionaryEntry myEntry in animalCollection)
{
    ((Animal)).Feed();
}

5. Iterator

Through the IEnumerable interface, you can use a foreach loop to get the object.
The process of iterating the collectionObject:
1 Call the GetEnumerator() method of the Collection to return an IEnumerator reference
This method can also be obtained through the implementation code of the IEnumerable interface.
2 Call the MoveNext() method of the IEnumerator interface to advance the enumeration to the next element of the collection.
3 If the MoveNext() method returns true, use the Current property of the IEnumerator interface to get the object's reference, which is used for the foreach loop.
4 Repeat the first two steps until MoveNext() returns false, the loop stops

Iterator is a block of code that provides all the values ​​to be used in the foreach loop in order.
Generally, this code block is a method, and you can also use property accessors and other code blocks as iterators.
The return value of the code block may be the IEnumerable or IEnumerator interface type:
1 If you want to iterate over a class, you can use the method IEnumerator(), and its return type is IEnumerator
2 If you want to iterate over a class member, use IEnumerable

In the iterator block, use the yield keyword to select the value to use in the foreach loop.
grammar:

yield return value;

For example:

public static IEnumerable SimpleList()
{
    yield return "string 1";
    yield return "string 2";
    yield return "string 3";
}

public static void Main(string[] args)
{
    foreach (string item in SimpleList())
    (item);

    ();
}

Here SimpleList is the iterator block, which is a method that uses the IEnumerable return type
You can return any type from the yield statement

The information can be interrupted and returned to the foreach loop process.
Syntax: yield break;

6. Iterators and collections

Iterators can be used to iterate over objects stored in a collection of directory types.
For example:

public new IEnumerator GetEnumerator()
{
    foreach (object animal in )
    yield return (Animal)animal;
}

Iterate over objects in the collection:

foreach (Animal myAnimal in animalCollection)
{
}

7. In-depth copy

Use the () method to perform shadow copying.
For value type members, no problem
But for reference type members, the new object and the member of the source object will point to the same reference object.
For example:

public class Content
{
    public int Val;
}
    
public class Cloner
{
    public Content MyContent = new Content();
    
    public Cloner(int newVal)
    {
         = newVal;
    }

    public object GetCopy()
    {
        return MemberwiseClone();
    }
}

implement:

Cloner mySource = new Cloner(5);
Cloner myTarget = (Cloner)();
int iVal1 = ;
 = 2;
int iVal2 = ;

result:
iVal1 is 5, iVal2 is 2

But sometimes what is needed is to refer to their respective objects separately, and it can be solved by using deep copy.
The standard way is to add an ICloneable interface, which has a Clone() method
This method does not take parameters and returns an object type.
For example:

public class Content
{
    public int Val;
}
    
public class Cloner : ICloneable
{
    public Content MyContent = new Content();
    public int iVal = 0;
    
    public Cloner(int newVal)
    {
         = newVal;
    }
    
    public object Clone()
    {
        Cloner clonedCloner = new Cloner();
         = iVal;
        return clonedCloner;
    }
}

Create the same Cloner object through the Val field of the Cloner object.
If there is a value member that needs to be copied, then this member must be added to the new object.
This will copy a new object that is the same as the source object and is independent of each other

Use GetCopy to Clone and execute the same program, the result is:
iVal1 is 5, iVal2 is 5

2. Comparison

1. Type comparison

When comparing objects, you need to know the type of the object first. You can use the GetType() method.
Used with the typeof() operator to determine the type of the object

if (() == typeof(MyComplexClass))
{
    // myObj is an instance of the class MyComplexClass.
}

Seal and unboxing

Background operations when processing value types:
Boxing is an interface type that converts a value type to a type or is implemented by a value type.
Unboxing is the opposite process
For example:
Structure type:

struct MyStruct
{
    public int Val;
}

Put the type structure in the object type variable to enclose the box:

MyStruct valType1 = new MyStruct();
 = 5;
object refType = valType1;

Here a valType1 of MyStruct type is created, and after assigning a value to the member, the box is enclosed into the object refType.
This way of encapsulation will contain a reference to a copy of the value type, rather than a reference to the source value.
verify:

 = 6;
MyStruct valType2 = (MyStruct)refType;

The result is 5 instead of 6

If a reference type is encapsulated, a reference containing the source value will be included.
For example:

class MyStruct
{
    public int Val;
}

Perform the same operation and the value obtained is 6

You can enclose the value type into an interface type:

interface IMyInterface
{
}
struct MyStruct : IMyInterface
{
    public int Val;
}

Enclose the structure into the IMyInterface type:

MyStruct valType1 = new MyStruct();
IMyInterface refType = valType1;

Unboxing:

MyStruct ValType2 = (MyStruct)refType;

The enclosure is carried out without user interference.
Unboxing a value requires explicit conversion (enclosing is an implicit conversion)
Before accessing the content of the value type, it must be unboxed.

is operator

The is operator can check whether the object is a given type, or whether it can be converted to a given type.
grammar:

is

1 If it is a class type, it is also the type, or inherits the type, or encloses it into the type, returns true
2 If it is an interface type, which is also the type, or the type that implements the interface, return true
3 If it is a value type, it is also the type, or if it is enclosed into this type, it returns true

2. Value comparison

Operator overloading

To overload operators, add operator type members to the class (must be static)
For example:
Overload + operator:

public class AddClass1
{
    public int val;

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

public class AddClass2
{
    public int val;
}

public class AddClass3
{
    public int val;
}

Operator overloading is similar to standard static method declarations, but it uses the keyword operator and operator itself
use:

AddClass1 op1 = new AddClass1();
 = 5;
AddClass2 op2 = new AddClass2();
 = 4;
AddClass3 op3 = op1 + op2;

The result value is 9

Note: If types are mixed, the operand order must be the same as the operator overload parameter order.

Operators that can be overloaded:
Unary operators: +, -,!, ~, ++, --, true, false
Binary operators: +, -, *, /, %, &, |, ^, <<, >>
Comparison operators: ==, !=, <,>, <=,>=
Notice:
If the true or false operator is overloaded, you can use a class in a boolean expression, for example if (op1) {}

Operators such as < and > must be overloaded in pairs, but other operators can be used to reduce the code.
For example:

class Addclass1
{
    public int val;

    public static bool operator >=(Addclass1 op1, Addclass2 op2)
    {
        return  >= ;
    }

    public static bool operator <(Addclass1 op1, Addclass2 op2)
    {
        return !(op1>= op2);
    }

    public static bool operator <=(Addclass1 op1, Addclass2 op2)
    {
        return  <= ;
    }

    public static bool operator >(Addclass1 op1, Addclass2 op2)
    {
        return !(op1 <= op2);
    }
}

Applicable to both == and !=, and often need to rewrite() and ()

class Addclass1
{
    public int val;

    public static bool operator ==(Addclass1 op1, Addclass1 op2)
    {
        return ( == );
    }

    public static bool operator !=(Addclass1 op1, Addclass1 op2)
    {
        return !(op1== op2);
    }

    public override bool Equals(object obj)
    {
        return val == ((Addclass1)obj).val;
    }

    public override int GetHashCode()
    {
        return val;
    }
}

IComparable and IComparer interfaces

IComparable and IComparer interfaces are standard ways to compare objects.
the difference:
IComparable is implemented in the class of the object to be compared, and can compare that object with another object.
IComparer is implemented in a separate class and can compare any two objects

.Net Framework provides the default implementation of the IComparer interface on the class Comparer. The class Comparer is located in the namespace and can compare culture-specific comparisons of simple types and any types that support IComparable interfaces.

public class SamplesComparer
{
    public static void Main()
    {
        String str1 = "llegar";
        String str2 = "lugar";
        ("Comparing \"{0}\" and \"{1}\" ", str1, str2);

        // Uses the DefaultInvariant Comparer.
        ("   Invariant Comparer: {0}", (str1, str2));

        // Uses the Comparer based on the culture "es-ES" (Spanish - Spain, international sort).
        Comparer myCompIntl = new Comparer(new CultureInfo("es-ES", false));
        ("   International Sort: {0}", (str1, str2))
    }
}

Generally, IComparable gives the default comparison code of the class, and other classes give the non-default comparison code.
IComparable provides a CompareTo() method to compare two objects and return an int value.
For example:

class Person : IComparable
{
    public string Name;
    public int Age;

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public int CompareTo(object obj)
    {
        if (obj is Person)
        {
            Person otherPerson = obj as Person;
            return  - ;
        }
        else
        {
            throw new ArgumentException( "Object to compare to is not a Person object.");
        }
    }
}

Main program code

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person("Jim", 30);
        Person person2 = new Person("Bob", 25);

        if ((person2) == 0)
        {
            ("Same age");
        }
        else if ((person2) > 0)
        {
            ("person 1 is Older");
        }
        else
        {
            ("person1 is Younger");
        }
    }
}

IComparer provides a Compare() method that accepts two objects to return an integer result.
For example:

public class PersonComparer : IComparer
{
    public static IComparer Default = new PersonComparer();

    public int Compare(object x, object y)
    {
        if (x is Person && y is Person)
        {
            return (((Person)x).Age, ((Person)y).Age);
        }
        else
        {
            throw new ArgumentException(
            "One or both objects to compare are not Person objects.");
        }
    }
}

Main program:

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person("Jim", 30);
        Person person2 = new Person("Bob", 25);

        if ((person1, person2) == 0)
        {
            ("Same age");
        }
        else if ((person1, person2) > 0)
        {
            ("person 1 is Older");
        }
        else
        {
            ("person1 is Younger");
        }
    }
}

3. Conversion

1. Overload the conversion operator

The implicit keyword is used to declare implicit user-defined type conversion operators
The explicit keyword is used for user-defined type conversion operators that are declarative.

For example:

public class ConvClass1
{
    public int val;

    public static implicit operator ConvClass2(ConvClass1 op1)
    {
        ConvClass2 returnVal = new ConvClass2();
         = ();
        return returnVal;
    }
}

public class ConvClass2
{
    public string val;

    public static explicit operator ConvClass1(ConvClass2 op1)
    {
        ConvClass1 returnVal = new ConvClass1();
         = Convert.ToInt32();
        return returnVal;
    }
}

use:

ConvClass1 op1 = new ConvClass1();
 = 5;
ConvClass2 op2 = op1;

Implicit conversion is used here, and the value at this time is the character "5"

ConvClass2 op1 = new ConvClass2();
 = "6";
ConvClass1 op2 = (ConvClass1)op1;

Display conversion is used here, and the value at this time is the number 6

2. As operator

The as operator can convert a type to a specified reference type.
grammar:

as

Applicable only to:
The type of 1 is type
2 Can be implicitly converted to type
3 Can be sealed into the type
If the conversion from cannot be converted from, the expression result is null

For example:

class ClassA : IMyInterface
{
}
    
class ClassD : ClassA
{
}

ClassA obj1 = new ClassA();
ClassD obj2 = obj1 as ClassD;

The result of obj2 is null

Use general type conversion, an exception will be thrown when an error occurs.
As will only assign null to the object, and as long as you judge whether the object is null, you will know whether the conversion is successful.

This is all about this article about C# collections, comparisons and transformations. I hope it will be helpful to everyone's learning and I hope everyone will support me more.