[Notas de estudio de C#] Tipo de referencia (2)

Insertar descripción de la imagen aquí


Objeto

Admite todas las clases de la jerarquía de clases .NET y proporciona servicios de bajo nivel a clases derivadas. Esta es la clase base definitiva para todas las clases .NET; es la raíz de la jerarquía de tipos.

En pocas palabras, es universal, es la clase principal de todos los tipos. Debido a que todas las clases en .NET derivan de Object, cada método definido en la clase Object está disponible para todos los objetos del sistema.

En la clase Object se proporcionan cuatro métodos de uso común, a saber, los métodos Equals, GetHashCode, GetType y ToString.

igual

int a = 1;
int b = 1;
if (a.Equals(b))
{
    
    
  Debug.Log("111"); -- 输出111
}

Person a = new Person();
Person b = 1;
if (a.Equals(b))
{
    
    
  Debug.Log("111"); -- 输出111
}

Equals es un juicio de igualdad, que es lo mismo que ==: para los tipos de valor, juzga si los valores son los mismos y para los tipos de referencia, juzga si las referencias son las mismas.

Obtener tipo

Se utiliza para obtener el tipo de instancia actual y el valor de retorno es System.Type. El método GetType no contiene ningún parámetro y es un método no estático.

Utilice Object.GetType() para devolver el tipo de objeto. La diferencia entre x.GetType() y typeof() es que GetType() es un método de objeto y se puede utilizar para que todas las variables obtengan sus tipos. Y typeof(xxx) solo puede poner tipos dentro pero no nombres de variables.

Encadenar

Convierte un objeto a su representación de cadena para que sea adecuado para su visualización.

Los tres métodos anteriores se pueden sobrecargar y reescribir.

Obtener código hash

Devuelve el valor hash del objeto. El valor hash de cada objeto es fijo. Este método no toma ningún parámetro y no es un método estático, por lo que se requiere una instancia para llamar al método. Dado que este método está definido en la clase Objeto, cualquier objeto puede llamar a este método directamente.


cadena

El tipo de cadena stringrepresenta una secuencia de cero o más caracteres Unicode. Lo que es especial es que, aunque la cadena es un tipo de referencia, ==cuando se usa para comparar, es una comparación de tipo de valor. Cabe señalar que la cadena es un tipo inmutable, lo que significa que cada vez que modificamos la cadena, en realidad creamos una nueva cadena.

texto textual

Utilice @palabras clave para identificar la cadena como texto textual; los caracteres de escape no serán reconocidos

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.
@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

cadena de formato compuesto

Utilice el método String.Format para combinar las variables en el elemento de formato, donde el número entre paréntesis representa el índice de variable correspondiente y lo :siguiente representa el tipo especificado de variable.

String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now);

También pueden existir varios índices idénticos al mismo tiempo.

string multiple = String.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Interpolación de cadenas

Uso $de palabras clave para identificar la interpolación de cadenas

string name = "Mark";
var date = DateTime.Now;
// Composite formatting:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {
      
      name}! Today is {
      
      date.DayOfWeek}, it's {
      
      date:HH:mm} now.");

(Para más uso, lea la documentación oficial , especialmente los métodos de la clase string. Lo vergonzoso es que hay tantos métodos de la clase string, pero String está completamente abrumado por StringBuilder en la mayoría de los casos)


Constructor de cadenas

Utilice el espacio de nombres System.Text para introducir el tipo.

Se puede decir que StringBuilder es un reemplazo completamente superior de String, que es una clase de cadena mutable. Mutabilidad significa que una vez que se crea una instancia de una clase, se puede modificar agregando, eliminando, reemplazando o insertando caracteres. Dado que String necesita generar una nueva cadena cada vez que se modifica, esto también genera algunos problemas de consumo de memoria que pueden ocurrir al operar en él. Entonces, para las cadenas que necesitan ser manipuladas, elegiríamos StringBuilder, pero el rendimiento depende del tamaño de la cadena, la cantidad de memoria que se asignará para la nueva cadena, el sistema que ejecuta el código y el tipo de operación.

Considere utilizar la clase String en las siguientes situaciones:

  • Cuando el código realiza una pequeña cantidad de cambios en la cadena. En estos casos, StringBuilder puede proporcionar mejoras de rendimiento insignificantes, por lo que String se puede utilizar directamente.
  • Al realizar un número fijo de operaciones de concatenación, especialmente cadenas literales. En este caso, el compilador puede combinar las operaciones concatenadas en una sola operación.
  • Cuando se debe realizar una operación de búsqueda extensa al generar una cadena. A la clase StringBuilder le faltan métodos de búsqueda como IndexOf o StartsWith. Para estas operaciones, el objeto StringBuilder debe convertirse en un String, lo que puede anular los beneficios de rendimiento del uso de StringBuilder. Para obtener más información, consulte Búsqueda de partes de texto en objetos StringBuilder.

Considere utilizar la clase StringBuilder en las siguientes situaciones:

  • Si se espera que el código realice una cantidad desconocida de cambios en la cadena en tiempo de diseño, por ejemplo, cuando se usa un bucle para concatenar una cantidad aleatoria de cadenas que contienen entradas del usuario.
  • Cuando se espera que el código realice una gran cantidad de cambios en las cadenas.

En general, String es más adecuado para algunas operaciones cortas y rápidas que implican concatenar cadenas o consultar la cadena completa. Si algunas cadenas deben cambiarse con frecuencia o modificarse dinámicamente, StringBuilder es más adecuado

Cómo funciona StringBuilder

¿Cómo modifica StringBuilder dinámicamente la longitud de una cadena? Supongamos que hay un StringBuilder con una longitud de cadena de 12. Si necesitamos agregar una cadena con una longitud = 20, StringBuilder primero arrojará la cadena al búfer con una longitud de 16. Cuando la longitud excede la longitud del buffer, significa que se necesita un buffer más grande y StringBuilder encontrará un nuevo buffer con el doble de tamaño (ahora 32). Luego copie el valor del búfer anterior y agregue aquellos caracteres nuevos que excedan la longitud original pero que no se hayan almacenado en el búfer anterior. Si aún excede el límite, repita el proceso anterior hasta que se complete el almacenamiento. (Si se excede la capacidad máxima establecida o no hay espacio adicional en la memoria, se informará un error)

public class Example
{
    
    
   public static void Main()
   {
    
    
      StringBuilder sb = new StringBuilder();
      ShowSBInfo(sb);
      sb.Append("This is a sentence.");
      ShowSBInfo(sb);
      for (int ctr = 0; ctr <= 10; ctr++) {
    
    
         sb.Append("This is an additional sentence.");
         ShowSBInfo(sb);
      }   
   }
   
   private static void ShowSBInfo(StringBuilder sb)
   {
    
    
      foreach (var prop in sb.GetType().GetProperties()) {
    
    
         if (prop.GetIndexParameters().Length == 0)
            Console.Write("{0}: {1:N0}    ", prop.Name, prop.GetValue(sb));
      }
      Console.WriteLine();
   }
}
// The example displays the following output:
//    Capacity: 16    MaxCapacity: 2,147,483,647    Length: 0
//    Capacity: 32    MaxCapacity: 2,147,483,647    Length: 19
//    Capacity: 64    MaxCapacity: 2,147,483,647    Length: 50
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 81
//    Capacity: 128    MaxCapacity: 2,147,483,647    Length: 112
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 143
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 174
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 205
//    Capacity: 256    MaxCapacity: 2,147,483,647    Length: 236
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 267
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 298
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 329
//    Capacity: 512    MaxCapacity: 2,147,483,647    Length: 360

Métodos proporcionados por StringBuilder

Es posible realizar llamadas a métodos individuales e ignorar el valor de retorno, como se muestra en el siguiente ejemplo.

using System;
using System.Text;

public class Example
{
    
    
   public static void Main()
   {
    
    
      StringBuilder sb = new StringBuilder();
      sb.Append("This is the beginning of a sentence, "); 
      sb.Replace("the beginning of ", ""); //替换所有字符A为字符B
      sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ");
      sb.Replace(",", "."); 
      Console.WriteLine(sb.ToString()); //只有在必须接受string类型时再转化为string
   }
}
// The example displays the following output:
//        This is a complete sentence.

Se pueden llamar una serie de métodos en una sola declaración. Esto puede resultar útil si desea escribir una única declaración que vincule operaciones consecutivas. El siguiente ejemplo combina las tres llamadas a métodos del ejemplo anterior en una sola línea de código.

using System;
using System.Text;

public class Example
{
    
    
   public static void Main()
   {
    
    
      StringBuilder sb = new StringBuilder("This is the beginning of a sentence, ");
      sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2, 
                                                 "complete ").Replace(",", ".");
      Console.WriteLine(sb.ToString());
   }
}
// The example displays the following output:
//        This is a complete sentence.

acceder a personajes

En mi opinión, acceder a los personajes es un gran problema con StringBuilder. StringBuilder no proporciona un método para acceder a sus caracteres internos, pero no es tan sencillo acceder a un determinado carácter en él, porque la memoria del búfer es discontinua. Si queremos encontrar un determinado carácter, debemos atravesar todo el buffer. Por lo tanto, un mejor método es ToStringconvertirlo en Stringun tipo mediante un método y luego usarlo char[Index]para acceder a los caracteres correspondientes.

iterar caracteres

Al iterar sobre los caracteres de un StringBuilder, se debe tener en cuenta que incluso para grandes "fragmentos" de objetos StringBuilder, el impacto en el rendimiento del uso de la propiedad Chars[] para el acceso basado en índices de uno o un pequeño número de caracteres es insignificante; normalmente, esta es una operación O(n). Al iterar caracteres en un objeto StringBuilder, hay un impacto significativo en el rendimiento, que es una operación O(n^2) (atravesando n caracteres * capacidad de búfer n).

Por lo tanto, cuando necesitamos iterar los caracteres de StringBuilder, la mejor manera es ToStringconvertirlos en Stringtipos mediante métodos y luego usarlos char[Index]para acceder a los caracteres correspondientes.

Caracteres de consulta

No existe ningún método para consultar caracteres en StringBuilder. Si desea consultar caracteres, solo puede convertir a Stringy luego usar el método String.IndexOfo String.StartWithpara encontrar el carácter o cadena correspondiente.

Dado que String y StringBuilder proporcionan demasiados métodos, no podemos profundizar aquí, se recomienda leer la documentación oficial.


dinámica

Finalmente, aprenda un poco sobre los tipos dinámicos. La dinámica en sí también es un objeto. En la mayoría de los casos, los tipos dinámicos se comportan de manera similar a los tipos de objetos. Específicamente, cualquier expresión que no sea nula se puede convertir a tipo dinámico. El tipo dinámico se diferencia del objeto en que el compilador no analiza ni verifica operaciones de tipo en expresiones que contienen el tipo dinámico. El compilador empaqueta información sobre la operación, que luego se utiliza para evaluar la operación en tiempo de ejecución. Durante este proceso, las variables de tipo dinámico se compilan en variables de tipo de objeto. Por lo tanto, los tipos dinámicos sólo existen en tiempo de compilación y no en tiempo de ejecución.

Lo especial de la dinámica es que no se analizará en tiempo de compilación, por lo que no se realizarán comprobaciones de seguridad. Por lo tanto, incluso si se define una dinámica incorrecta, el compilador no informará ningún error. Solo se informará un error cuando ocurra un error durante el tiempo de ejecución.

En segundo lugar, dado que la esencia de la dinámica es Objeto, también se puede convertir implícitamente a cualquier tipo. Y esta es también su mayor ventaja. Por ejemplo:

dynamic x = 10; //此时x为int
x = x + "Hello"; // x 现在是一个字符串
x = x.ToUpper(); // x 仍然是一个字符串
x = 8;  // x 现在保存的是一个int类型的变量
x = x * 8; // x现在仍然是int

En el ejemplo anterior, definimos x como dinámico, se puede ver que debe ser de tipo int, luego lo convertimos en una cadena y luego operamos en la cadena. Luego se asigna x al tipo int. x cambia su tipo dinámicamente a lo largo del programa. Esto es algo que var no puede hacer, porque el compilador inferirá automáticamente su tipo bajo la palabra clave var, por lo que es una clase estática. Generalmente, no podemos realizar la conversión de tipos sin una conversión explícita.

Si desea implementarlo usando solo clases estáticas, necesita crear nuevas variables correspondientes a los tipos estáticos diseñados. Si desea implementar el proceso anterior para variables de tipo estático x, solo será más complicado:

int x=10;
String y = x.ToString();
y=y+"Hello";
y = y.ToUpper();
x = 8;
x = x* 8

El tipo dinámico de dinámica es en realidad muy similar a la naturaleza variable de algunos lenguajes de programación. Por lo tanto, también utilizamos tipos dinámicos para interactuar con lenguajes de scripting.

Supongo que te gusta

Origin blog.csdn.net/milu_ELK/article/details/132084539
Recomendado
Clasificación